remix
Skill0 starsChanged 2 months agoMITView on GitHub
Build and review Remix 3 applications using the `remix` npm package and subpath imports. Use when working on Remix app structure, routes, controllers, middleware, validation, data access, auth, sessions, file uploads, server setup, UI components, hydration, HMR, navigation, or tests.
- Reads credentials
7 other projects use a version of this.
Adopted by
Most recently taken up by
- SigmaMatrix-AI/tapvidtheir own version, first seen Nov 8, 2026
- G1Joshi/Agent-Skillstheir own version, first seen Oct 13, 2026
- Mindrally/skillstheir own version, first seen Oct 8, 2026
- paean-ai/deeptidetheir own version, first seen Oct 8, 2026
- remix-run/remixtheir own version, first seen Oct 8, 2026
- authdog/agent-skillstheir own version, first seen Sep 18, 2026
Other versions7 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 7
- remix-run/remix★ 33ksame name
- paean-ai/deeptide★ 1.1ksame name
- Mindrally/skills★ 275same name
- basezh/agent-skills-on-base★ 15same name
- G1Joshi/Agent-Skills★ 15same name
- SigmaMatrix-AI/tapvid★ 4same name
- authdog/agent-skills★ 0same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository10 other files it gives its agents.
- create-pull-requestSkill
- deep-researchSkill
- herdrSkill
- pr-review-loopSkill
- readme-writerSkill
- sandi-metz-rulesSkill
- skill-creatorSkill
- tearing-down-a-merged-worktreeSkill
- test-auditSkill
- worktree-spaceSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
47 rules. 0 are common, 15 are distinctive, and 32 are very specific to this project.
0
Common
Most of the 7 edited versions we read keep these.
15
Distinctive
This author's own choices. Worth a look.
32
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 8
Use this skill for end-to-end Remix app work.
- Distinctive: line 32
Use this skill for:
- Distinctive: line 43
Use the table below to find candidates.
- Very specific: line 72
Start from the server contract: Add or update app/routes.ts before wiring handlers or UI.
- Very specific: line 75
Add middleware deliberately: Keep fast-exit middleware early and request-enriching middleware later.
- Very specific: line 77
Hydrate only when necessary: Prefer server-rendered UI.
- Distinctive: line 78
Test the narrowest meaningful layer: Prefer router tests for route behavior.
- Distinctive: line 83
Use these root directories consistently:
- Distinctive: line 104
When code could live in multiple places:
- Distinctive: line 106
Put it in the narrowest owner first.
- Distinctive: line 107
If it belongs to one route, keep it with that route.
- Very specific: line 108
If it is shared UI across route areas, move it to app/ui/.
- Very specific: line 109
If it is request lifecycle setup, keep it in app/middleware/.
- Very specific: line 110
If it is schema, query, persistence, or startup data logic, keep it in app/data/.
- Very specific: line 111
Use app/utils/ only as a last resort for truly cross-layer helpers.
- Very specific: line 115
Put top-level leaf actions in app/actions/controller.tsx
- Very specific: line 117
Add app/actions/<route-key>/controller.tsx for each nested route map that needs actions or controller middleware, and map it explicitly …
- Distinctive: line 119
Keep route-local UI and helpers next to the controller that owns them
- Very specific: line 121
If a top-level leaf grows into a route map, move its handler into the nested route-key controller and update app/router.ts to map that …
- Very specific: line 127
Use renderWith(...), renderToStream(...), and createHtmlResponse(...) only when an application intentionally owns a custom renderer …
- Very specific: line 128
Put pure support code in focused app/utils/<topic>.ts modules.
- Very specific: line 129
Do not introduce page-data intermediary shapes only to keep route-specific renderers away from render(...).
- Very specific: line 133
Do not create app/lib/ as a generic dumping ground
- Very specific: line 134
Do not create app/components/ as a second shared UI bucket when app/ui/ already owns that role
- Very specific: line 135
Do not create app/controllers/.
- Very specific: line 136
Do not put shared cross-route UI in app/actions/
- Very specific: line 137
Do not create standalone root action files.
- Very specific: line 138
Do not put nested route-map keys in a controller's actions
- Very specific: line 139
Do not register normal app leaf routes directly in app/router.ts when they belong in a controller
- Distinctive: line 140
Do not rely on controller middleware from one controller to protect another controller.
- Very specific: line 141
Do not put middleware or persistence helpers in app/utils/ when they have a clearer home
- Very specific: line 145
Import from remix/<subpath>, never import { ...
- Very specific: line 146
Treat app/routes.ts as the source of truth for URLs.
- Very specific: line 155
Prefer host-element mixins via mix={mixin(...)} for behavior and styling instead of inventing custom host prop conventions.
- Distinctive: line 161
Never ship demo secrets. In non-test environments, require session and provider secrets from the environment and fail fast if they are …
- Very specific: line 162
Use hardened cookies: httpOnly always, sameSite by default, and secure when serving over HTTPS
- Very specific: line 164
Use requireAuth() to protect authenticated route areas, but still authorize resource ownership inside handlers and data writes
- Distinctive: line 165
Add CSRF protection when browser forms mutate state using cookie-backed sessions
- Distinctive: line 166
Add CORS only for endpoints that must be called cross-origin.
- Very specific: line 167
Prefer JSX or remix/html-template for HTML generation so escaping stays correct
- Very specific: line 172
Prefer server and router tests first.
- Very specific: line 173
Keep controller tests shaped like controllers: root route behavior belongs in app/actions/controller.test.ts(x), and nested route-map …
- Very specific: line 175
Use routes.<name>.href(...) in tests so URLs stay coupled to the route contract
- Very specific: line 178
Use component tests only for interactive or DOM-specific behavior.
- Distinctive: line 179
Prefer one representative behavior test over many repetitive assertion variants
- Distinctive: line 204
Use this map to find the right package quickly.
- Very specific: line 452
Only add clientEntry(...) and run(...) when the component needs browser interactivity or browser-only APIs.
“Common” is measured: kept by at least 6 in 10 of the 7 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Build a Remix App
Use this skill for end-to-end Remix app work. This skill helps you choose the right layer first, reach for the right package, and avoid the most common Remix-specific mistakes.
Full Package Documentation
This skill is the quick guide. When you need fuller API documentation, examples, or package-specific details for a remix/* subpath, first look for a README next to the relevant generated source file in the published remix package: node_modules/remix/src/<subpath>/README.md. These published README files are generated mirrors; in the Remix source repository, the canonical README lives in the owning packages/* package and the packages/remix/src/**/README.md mirrors are intentionally ignored. If that README does not exist, look for the nearest parent README because some subpaths share their parent package documentation.
Examples:
remix/router->node_modules/remix/src/fetch-router/README.mdremix/ui/button->node_modules/remix/src/ui/button/README.md
What Remix Is
Remix 3 is a server-first web framework built on Web APIs such as Request, Response, URL, and FormData. All packages ship from a single npm package, remix, and are imported via subpath. There is no top-level remix import.
A Remix app has four main pieces:
- Routes in
app/routes.tsdefine the typed URL contract and powerhref()generation. - Controllers in
app/actionsimplement that contract and returnResponseobjects. - Middleware composes request lifecycle behavior and populates typed context via
context.set(Key, value). - Components render UI with
remix/ui. This is not React. A component receives ahandle, reads current props fromhandle.props, and returns a zero-argument render function.
When To Use This Skill
Use this skill for:
- new features or refactors that touch routing, controllers, middleware, data, auth, sessions, UI, or tests
- reviewing Remix app code for correctness, architecture, or framework usage
- answering "how should this be structured in Remix?" questions
- finding the right package, reference doc, or default pattern for a task
Load Only The References You Need
Classify the task first, then load the smallest useful reference set. Each reference file starts with a "What This Covers" section that lists the topics inside it — read that first to confirm the file is relevant before reading the rest.
Use the table below to find candidates. Loading more than two or three files at once is usually a sign that the task hasn't been narrowed enough yet.
| Task involves... | Start with |
| Defining URLs, writing controllers and actions, returning responses | references/routing-and-controllers.md |
| Composing the request lifecycle, ordering middleware, bridging to a server, development HMR | references/middleware-and-server.md |
| Compiling and serving browser modules, asset URL namespaces, preloads, browser HMR | references/assets-and-browser-modules.md |
| Parsing input, validating with schemas, defining tables, querying, migrations | references/data-and-validation.md |
| Per-browser state, login flows, route protection, identity | references/auth-and-sessions.md |
Component setup, state, lifecycle, updates, queueTask, context | references/component-model.md |
| Event handlers, styles, refs, click/key behavior, simple animations | references/mixins-styling-events.md |
clientEntry, run, <Frame>, navigation, browser HMR update handling, <head> | references/hydration-frames-navigation.md |
| Router tests, component tests, test isolation | references/testing-patterns.md |
| Spring physics, tweens, layout transitions | references/animate-elements.md |
| Authoring custom reusable mixins | references/create-mixins.md |
Common bundles:
- Form or CRUD feature -> routing, data and validation, testing; add auth if user-specific
- Protected area -> auth and sessions, routing, testing
- Interactive widget -> component model, mixins and styling; add hydration only if it runs in the browser
- Browser asset pipeline -> assets and browser modules, hydration, middleware and server
- Development HMR -> middleware and server, assets and browser modules, hydration
- File upload -> middleware and server, data and validation, testing
- Navigation or frames -> hydration, frames, navigation
Default Workflow
- Classify the change. Decide whether it changes the route contract, request lifecycle, data model, auth or session behavior, or only UI.
- Start from the server contract. Add or update
app/routes.tsbefore wiring handlers or UI. - Put code in the narrowest owner. Favor route-local code first, then promote only when reuse is real.
- Make the server path correct before adding browser behavior. A route should return the right
Responseviarouter.fetch(...)before you addclientEntry(...), animations, or DOM effects. - Add middleware deliberately. Keep fast-exit middleware early and request-enriching middleware later. Export a typed
AppContextfrom the middleware stack and use it in controllers. - Validate input at the boundary. Parse and validate
Request,FormData, params, cookies, and external payloads before they reach rendering or persistence logic. - Hydrate only when necessary. Prefer server-rendered UI. Use
clientEntry(...)andrun(...)only for real browser interactivity or browser-only APIs. - Test the narrowest meaningful layer. Prefer router tests for route behavior. Use component tests when the behavior is truly interactive or DOM-specific.
- Finish with verification. Re-read the route flow, confirm auth and authorization boundaries, and run the smallest relevant test and typecheck loop.
Project Layout
Use these root directories consistently:
app/for runtime application codedb/for migrations and local database files- root
public/for static assets served as-is from the app root test/for shared helpers, fixtures, and integration coveragetmp/for uploads, caches, local session files, and other scratch data
Inside app/, organize by responsibility:
actions/for controller-owned route handlers, route-local response rendering, and route-local UI/helpers that are not shared across route areasdata/for schema, queries, persistence setup, migrations, and runtime data initializationmiddleware/for request lifecycle concerns such as auth, sessions, uploads, and database injectionpublic/directories inside the narrowest owner for browser-reachable source code, with the browser runtime entrypoint atapp/actions/public/entry.tsui/for shared cross-route UI primitivesutils/only for genuinely cross-layer helpers that do not clearly belong elsewhereroutes.tsfor the shared server-and-browser route contract and type-safe href generationrouter.tsfor router setup and wiring
Placement Precedence
When code could live in multiple places:
- Put it in the narrowest owner first.
- If it belongs to one route, keep it with that route.
- If it is shared UI across route areas, move it to
app/ui/. - If it is request lifecycle setup, keep it in
app/middleware/. - If it is schema, query, persistence, or startup data logic, keep it in
app/data/. - Use
app/utils/only as a last resort for truly cross-layer helpers.
Route Ownership
- Put top-level leaf actions in
app/actions/controller.tsx - A controller's
actionsobject contains only direct leaf route keys from the route map passed torouter.map(...) - Add
app/actions/<route-key>/controller.tsxfor each nested route map that needs actions or controller middleware, and map it explicitly withrouter.map(routes.<routeKey>, controller) - Name directories under
app/actions/after route-map keys, not URL path segments - Keep route-local UI and helpers next to the controller that owns them
- Move shared cross-route UI to
app/ui/ - If a top-level leaf grows into a route map, move its handler into the nested route-key controller and update
app/router.tsto map that route map explicitly
Response Rendering And Utilities
- Install
render()fromremix/middleware/renderin the router middleware stack for normal Remix UI applications. Passrender({ assets })when source-basedclientEntry()modules need browser URLs - Render UI responses at the action boundary with
context.render(node, init). Status, headers, and other response policy remain explicit in the action - Use
renderWith(...),renderToStream(...), andcreateHtmlResponse(...)only when an application intentionally owns a custom renderer contract or replaces the standard UI response pipeline - Put pure support code in focused
app/utils/<topic>.tsmodules. Formatting, MIME classification, path parsing, sorting, and normalization should be testable without a router, request context, orResponse, and should not import fromapp/actions,remix/ui/server, orremix/response/* - Do not introduce page-data intermediary shapes only to keep route-specific renderers away from
render(...); keep response assembly in actions and extract only the pure helpers
Layout Anti-Patterns
- Do not create
app/lib/as a generic dumping ground - Do not create
app/components/as a second shared UI bucket whenapp/ui/already owns that role - Do not create
app/controllers/; Remix app route handlers live underapp/actions/ - Do not put shared cross-route UI in
app/actions/ - Do not create standalone root action files; put root route actions in
app/actions/controller.tsx - Do not put nested route-map keys in a controller's
actions - Do not register normal app leaf routes directly in
app/router.tswhen they belong in a controller - Do not rely on controller middleware from one controller to protect another controller; add controller middleware explicitly in each controller that needs it
- Do not put middleware or persistence helpers in
app/utils/when they have a clearer home
Core Remix Rules
- Import from
remix/<subpath>, neverimport { ... } from 'remix' - Treat
app/routes.tsas the source of truth for URLs. Useroutes.<name>.href(...)for redirects, links, tests, and internal URL construction - Controllers should return explicit
Responseobjects, including redirects, 404s, and validation failures. At the route boundary, prefer returning aResponsefor expected outcomes (validation errors, conflicts, not found) over throwing for control flow router.map(routes, controller)maps only the direct leaf routes inroutes; nested route maps must be mapped with their own explicit controllers- Model HTTP behavior explicitly. Status codes, headers, redirects, cache rules, and content types are part of the route contract
- Make the server route correct first. A POST should already return the right HTML, redirect, or error response on its own before
clientEntry(...)layers interactivity on top - Validate input at the boundary using
remix/data-schema(andremix/data-schema/form-datafor forms).parseSafemakes the failure path a return value instead of an exception - Derive
AppContextfrom the middleware stack soget(databaseContext),get(Session),get(Auth), and similar keys stay typed. If the controller never reads from context, it doesn't need the harness - Outside actions and controllers, only use
getContext()whenasyncContext()is in the middleware stack - Remix Component is not React: write
function Name(handle: Handle<Props>) { return () => ... }, read props fromhandle.props, keep state in setup-scope variables, callhandle.update()explicitly, and do DOM-sensitive work in event handlers orqueueTask(...), not in render - Prefer host-element mixins via
mix={mixin(...)}for behavior and styling instead of inventing custom host prop conventions. Usemix={[...]}only when composing multiple mixins - Keep short, one-off static styles inline with
mix={css(...)}. Extract a module-scoped style descriptor when it forms a reused visual recipe, has substantial selectors, media queries, or keyframes, or is large enough to obscure the component. Export a style descriptor only after multiple modules need the same visual recipe; otherwise keep it with its narrowest owner - Hydrated
clientEntry(...)props must be serializable. Do not pass functions, class instances, or opaque runtime objects
Security And Session Defaults
- Never ship demo secrets. In non-test environments, require session and provider secrets from the environment and fail fast if they are missing
- Use hardened cookies:
httpOnlyalways,sameSiteby default, andsecurewhen serving over HTTPS - Regenerate session IDs on login, logout, and privilege changes
- Use
requireAuth()to protect authenticated route areas, but still authorize resource ownership inside handlers and data writes - Add CSRF protection when browser forms mutate state using cookie-backed sessions
- Add CORS only for endpoints that must be called cross-origin. Prefer same-origin by default
- Prefer JSX or
remix/html-templatefor HTML generation so escaping stays correct - Validate uploads for size, type, and destination. Treat filenames and content as untrusted input
Testing Defaults
- Prefer server and router tests first. Drive the app with
router.fetch(new Request(...))and assert on the returnedResponse - Keep controller tests shaped like controllers: root route behavior belongs in
app/actions/controller.test.ts(x), and nested route-map behavior belongs beside that route-key controller - Build a fresh router per test or per suite so sessions, in-memory storage, and database state stay isolated
- Use
routes.<name>.href(...)in tests so URLs stay coupled to the route contract - For auth or session scenarios, use a test cookie and
createMemorySessionStorage()instead of production storage - Co-locate tests for pure
app/utilshelpers beside their modules. Test response behavior through router or controller tests - Use component tests only for interactive or DOM-specific behavior. Render with
createRoot(...), interact with the real DOM, and callroot.flush()between steps - Prefer one representative behavior test over many repetitive assertion variants
Common Mistakes To Avoid
- Treating Remix Component like React and reaching for hooks or implicit rerendering
- Importing from a top-level
remixentry instead of a subpath - Adding
clientEntry(...)before the server-rendered route behavior is correct - Passing non-serializable props into
clientEntry(...) - Calling
getContext()withoutasyncContext()in the middleware stack - Getting middleware order wrong; fast exits like static files belong early, request enrichment later
- Skipping boundary validation and trusting raw
FormData, params, cookies, or external payloads - Letting route-local domain errors leak out of the controller. Translate expected outcomes (validation, conflicts, not-found) into the HTTP
Responsethe route means to return rather than throwing a customErrorsubclass and catching it elsewhere - Reaching for
createCookiewhen a tamper-sensitive or server-managed per-browser fact really wantsremix/session. If editing the value would be a bug, use a session - Building a JSON-only RPC layer when a normal form POST, redirect, or resource route would be simpler. Fetch-from-the-client is a layer on top of sound route behavior, not a replacement for it
- Treating JSON state endpoints and
<Frame>reloads as mutually exclusive patterns. Pick the lightest sync mechanism that fits the UX; small widgets may reasonably poll a JSON endpoint - Assuming authentication is enough without per-resource authorization checks
- Dropping shared code into vague buckets like
utils.ts,helpers.ts, orcommon.tswhen ownership is known - Recreating the old
app/controllersor standalone root action file layout instead of using controllers underapp/actions - Putting nested route-map keys inside a controller
actionsobject. Map nested route maps explicitly inapp/router.ts - Treating direct
router.get(...)/router.post(...)registrations as the default app structure instead of using controllers - Assuming controller middleware applies to controllers registered for nested route maps
- Writing only component tests for a feature whose main behavior is really an HTTP route concern
Package Map
Use this map to find the right package quickly. Each entry says what the package is for, not just what it exports. Open the linked reference file when you need full examples.
Routing, Server, and Responses
remix/router— the router itself. Use forcreateRouter, controllers, middleware types, and registering routesremix/routes— declarative route builders. Use forroute,get,post,put,del,form,resourceswhen definingapp/routes.tsremix/node-fetch-server— default Node adapter for new apps. UsecreateRequestListenerwithnode:http,node:https, ornode:http2inserver.tswhen booting the template-style appremix/node-hmr— optional development Node HMR runner for rapid UI edits. Useruninhmr.tsto superviseserver.tsbehind anhmrscript, and usecreateHmrReadyFetchwhen a stable public proxy should wait for child server readiness during updatesremix/node-hmr/runtime— child-process runtime API for code running underremix/node-hmr. Use to create browser HMR channels for asset servers and to emit server readiness after the child server starts listeningremix/node-hmr/types— type-only entry forimport.meta.hotin Node modulesremix/assets— browser asset server. Use forcreateAssetServerwhen serving compiled scripts and styles, getting public hrefs, emitting preloads, and wiring browser HMR. Configure abasePath; use optional directorymountsconfiguration when the default mounts that serveappatappandnode_modulesatnpmare not enough; useallowFiles/denyFilesfor path and glob rules; and use exact package names inallowPackagesfor package-level access. Shared compiler options such astarget,sourceMaps,sourceMapSourcePaths, andminifylive at the top levelremix/assets/types/hmr— type-only entry forimport.meta.hotin browser modules compiled byremix/assetsremix/headers—SuperHeadersplus typed header parsers and builders. Use the default export when you want aHeaderssubclass with typed accessors likeheaders.contentType,headers.cacheControl, andheaders.setCookie; use named classes such asCacheControl,ContentDisposition, andVarywhen working with individual header valuesremix/response/redirect—redirect(href, status?). Use for the canonical "POST then redirect" pattern and other location changesremix/response/html—createHtmlResponse. Use when you need an HTMLResponsefrom a string or stream without rendering throughremix/uiremix/response/compress—compressResponse. Use when compressing one-off responses outsidecompression()middlewareremix/response/file— file-download responses. Use forContent-Disposition: attachmentresponsesremix/route-pattern— low-level URL matching and generation. UseRoutePatternorcreateMatcherwhen working with raw patterns outside the router.href(...)encodes pathname and search params for you, andmatch(...)returns decoded paramsremix/route-pattern/specificity— pattern ranking helpers. Use only when building custom matcher or reporting logic outside the normal router/matcher APIsremix/fetch-proxy— Fetch-based HTTP proxying. Use to forward a request to another origin; passxForwardedHeaderswhen the upstream needs forwarded proto, host, and port. It also rewrites proxiedSet-Cookiedomain/path attributes by default
Data, Validation, and Persistence
remix/data-schema— schema builders for runtime validation. Use forparseandparseSafeto validate any input that crosses a trust boundary, and.transform(...)when validated output should map to a different value or typeremix/data-schema/checks— common check helpers (email,minLength,maxLength, etc.). Use to compose into a schemaremix/data-schema/coerce— coercion helpers for strings, numbers, booleans, dates, and ids. Use when input arrives as a string but should be a typed valueremix/data-schema/form-data—f.objectandf.fieldfor parsingFormDatadirectly. Use in actions that read browser formsremix/data-schema/lazy— recursive or mutually-referential schemas. Use when a schema needs to refer to itself or another schema that is declared laterremix/data-table— typed tables and the sharedDatabaseAPI. Usetableandcolumnwhen modeling persisted data, then create a concrete database from the matching dialect package. Integration packages can implementDatabaseDriverand extendDatabaseto add another SQL dialectremix/data-table/sqlite,remix/data-table/postgres,remix/data-table/mysql— concrete database integrations. UsecreateSqliteDatabase,createPostgresDatabase, orcreateMysqlDatabase. SQLite accepts Node, Bun, and compatible synchronous clients with the sharedprepare/execsurfaceremix/data-table/migrations— migration authoring and registries. Use forcreateMigrationandcreateMigrationRegistry; run migrations withDatabase.migrate()remix/data-table/migrations/node—loadMigrationsfrom disk. Use in startup scripts that apply migrationsremix/data-table/operators— query operators such asinList(...). Use whenwhereclauses need set or comparison logicremix/data-table/sql-helpers— SQL helper utilities for database integrations or advanced query work. Avoid this in normal app code unless you are intentionally working below the table/query API
Auth, Sessions, and Cookies
remix/session— theSessionobject:get,set,flash,unset,regenerateId. Use for any per-browser state where tampering would be a bug (login, "I submitted this form already", cart, flash messages)remix/middleware/session—session(cookie, storage). Use to wire a session cookie and storage backend into the middleware stackremix/session-storage/fs,remix/session-storage/memory,remix/session-storage/cookie— storage backends. Usefs-storagefor single-process apps,memory-storagefor tests,cookie-storagefor stateless deployments where data fits in a cookieremix/session-storage/redis— Redis-backed storage. Use for multi-process or multi-host deploymentsremix/session-storage/memcache— Memcache-backed storage. Same multi-host use case as Redisremix/cookie—createCookiefor plain signed/unsigned cookies. Use for non-sensitive preferences where the client is allowed to control the value (theme, locale, dismissed banner). For state where tampering matters, preferremix/sessionremix/auth— credentials, OAuth, and OIDC providers. Use to define how identity is verified, start/finish external login, and refresh stored OAuth/OIDC token bundles withrefreshExternalAuth(...)remix/middleware/auth—auth({ schemes }),requireAuth, theAuthcontext key. Use to resolve identity into the request context and to gate routes
UI, Hydration, and Browser Behavior
remix/ui— the component runtime: components, core mixins,clientEntry,run,<Frame>, navigation helpers, andcreateRoot. Use for app UI behaviorremix/ui/server— low-level server rendering withrenderToStreamandrenderToString. Normal apps should installrender()fromremix/middleware/render; use this subpath for custom pipelines and static string renderingremix/ui-hmr— direct Remix UI component HMR transforms. Use only when writing a custom module hook or build integrationremix/ui-hmr/node— Node import hook for Remix UI component HMR. Use with--import remix/ui-hmr/nodein development servers that run throughremix/node-hmrremix/ui-hmr/assets—remix/assetsloader for Remix UI component HMR. UseuiHmr()increateAssetServer({ scripts: { loaders } })during developmentremix/ui/dev/refresh— development refresh support used by HMR tooling, not normal application coderemix/ui/animation— animation APIs:animateEntrance,animateExit,animateLayout,spring,tween, andeasingsremix/ui/<primitive>— UI primitives, mixins, and component helpers. Current subpaths includeremix/ui/accordion,remix/ui/anchor,remix/ui/button,remix/ui/checkbox,remix/ui/combobox,remix/ui/input,remix/ui/listbox,remix/ui/menu,remix/ui/popover, andremix/ui/selectremix/ui/test— component test rendering helpers such asrenderremix/ui/jsx-runtimeandremix/ui/jsx-dev-runtime— JSX transform targets. Configured intsconfig.json, rarely imported directlyremix/html-template— escaped HTML template literals. Use when generating HTML outside the component system (RSS feeds, email bodies, error pages)remix/file-storage— backend-agnosticFilestorage interface. Use as the type bound for upload destinationsremix/file-storage/fs,remix/file-storage/memory,remix/file-storage/s3— storage backends. Use to implement an upload destination
Middleware
remix/middleware/render—render({ assets?, onError? })for the standard Remix UI renderer andrenderWith(factory)for custom request-scoped renderers. Normal UI actions returncontext.render(node, init)remix/middleware/static—staticFiles(dir). Use to serve files frompublic/exactly as they exist on diskremix/middleware/form-data—formData(). Use to parseFormDataonce and expose it viaget(FormData)instead of callingawait request.formData()in each actionremix/form-data-parser— lower-levelparseFormData,FileUpload. Use when implementing custom upload handlers. Upload handler errors propagate directlyremix/multipart-parserandremix/multipart-parser/node— low-level multipart stream parsing.MultipartPart.headersis a plain object keyed by lower-case header name; read values with bracket notation such aspart.headers['content-type']remix/middleware/compression—compression(). Use for text-like responsesremix/middleware/logger—logger(). Use in development for request logs; passcolorsto force terminal color output on or offremix/middleware/method-override—methodOverride(). Use when HTML forms needPUT,PATCH, orDELETEremix/middleware/async-context—asyncContext(),getContext(). Use when helpers outside actions need request context without threading it through every callremix/middleware/cors—cors(opts?). Use for endpoints called cross-originremix/middleware/csrf—csrf(opts?). Use when session-backed forms mutate state and need synchronizer-token CSRF protectionremix/middleware/cop— cross-origin protection. Use to reject unsafe cross-origin browser requests
Test
remix/test—describe,it, and lifecycle hooks. Use as the test frameworkremix/test/cli— programmatic test runner APIs such asrunRemixTestremix/node-fetch-server/test—createTestServerfor end-to-end tests that need a real local HTTP server around a Fetch handlerremix/cli— programmatic Remix CLI API. Use theremixexecutable for project commands such asremix test,remix routes,remix doctor, andremix versionremix/assert— assertion helpers. Use in place ofnode:assertso messages render cleanly in the runnerremix/terminal— ANSI styles, color detection, style factories, and testable terminal streams. Use for CLIs and terminal output instead of hand-rolled escape sequencesremix/fs— small filesystem helpers such asopenLazyFileandwriteFile. Use in Node-only app or tooling code when you need lazy file responses or safe file writesremix/lazy-file—LazyFileprimitives and byte-range helpers. Use when implementing file or range responses below the higher-level response/file helpersremix/mime— content-type and MIME detection helpers. Use instead of maintaining app-local extension mapsremix/tar-parser— streaming tar parsing. Use for import/export tooling that consumes tar archives
Canonical Patterns
Define routes first
import { form, get, post, resources, route } from 'remix/routes'
export const routes = route({
home: '/',
contact: form('contact'),
books: {
index: '/books',
show: '/books/:slug',
},
auth: route('auth', {
login: form('login'),
logout: post('logout'),
}),
admin: route('admin', {
index: get('/'),
books: resources('books', { param: 'bookId' }),
}),
})Type controllers against the route contract
import { createController } from 'remix/router'
import { databaseContext } from '../middleware/database.ts'
import { routes } from '../routes.ts'
export default createController(routes.books, {
actions: {
async index({ get }) {
let db = get(databaseContext)
let allBooks = await db.findMany(books, { orderBy: ['id', 'asc'] })
return render(<BooksIndexPage allBooks={allBooks} />)
},
async show({ get, params }) {
let db = get(databaseContext)
let book = await db.findOne(books, { where: { slug: params.slug } })
if (!book) return new Response('Not Found', { status: 404 })
return render(<BookShowPage book={book} />)
},
},
})Register Controllers Explicitly
import { createRouter } from 'remix/router'
import rootController from './actions/controller.tsx'
import adminController from './actions/admin/controller.tsx'
import adminBooksController from './actions/admin/books/controller.tsx'
import authController from './actions/auth/controller.tsx'
import authLoginController from './actions/auth/login/controller.tsx'
import booksController from './actions/books/controller.tsx'
import contactController from './actions/contact/controller.tsx'
import { routes } from './routes.ts'
export const router = createRouter({ middleware })
router.map(routes, rootController)
router.map(routes.contact, contactController)
router.map(routes.books, booksController)
router.map(routes.auth, authController)
router.map(routes.auth.login, authLoginController)
router.map(routes.admin, adminController)
router.map(routes.admin.books, adminBooksController)Compose middleware deliberately
import { createRouter } from 'remix/router'
let middleware = []
if (process.env.NODE_ENV === 'development') {
middleware.push(logger())
}
middleware.push(compression())
middleware.push(staticFiles('./public'))
middleware.push(formData())
middleware.push(methodOverride())
middleware.push(session(cookie, storage))
middleware.push(asyncContext())
middleware.push(loadDatabase())
middleware.push(loadAuth())
let router = createRouter({ middleware })Validate, mutate, and respond
import { createController } from 'remix/router'
import { redirect } from 'remix/response/redirect'
import * as s from 'remix/data-schema'
import * as f from 'remix/data-schema/form-data'
import { Session } from 'remix/session'
import { databaseContext } from '../middleware/database.ts'
import { routes } from '../routes.ts'
let bookSchema = f.object({
slug: f.field(s.string()),
title: f.field(s.string()),
})
export default createController(routes.books, {
actions: {
async create({ get }) {
let parsed = s.parseSafe(bookSchema, get(FormData))
if (!parsed.success) {
return render(<NewBookPage errors={parsed.issues} />, { status: 400 })
}
let db = get(databaseContext)
let book = await db.create(books, parsed.value)
let session = get(Session)
session.flash('message', `Added ${book.title}.`)
return redirect(routes.books.show.href({ slug: book.slug }))
},
},
})This shape works without JavaScript, returns a Response for every outcome, and is ready for clientEntry(...) interactivity when the UI needs it.
Build UI from handle props plus render
import { on, type Handle } from 'remix/ui'
function Counter(handle: Handle<{ initialCount?: number; label: string }>) {
let count = handle.props.initialCount ?? 0
return () => (
<button
mix={on('click', () => {
count++
handle.update()
})}
>
{handle.props.label}: {count}
</button>
)
}Only add clientEntry(...) and run(...) when the component needs browser interactivity or browser-only APIs.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

