If you've used Claude Code or Cursor on a Remix project, you've probably seen it drift toward patterns that belong in other React frameworks — Express-style middleware, React Query for everything, client-side fetching where loaders should live.
Remix has a specific mental model: loaders and actions own the data layer, the file system is the router, and progressive enhancement is a first-class feature. AI tools that don't know this produce code that works in isolation but fights the framework constantly.
A CLAUDE.md file at the repo root is the fix. It gives every AI session the Remix mental model upfront, before any code is generated.
Here are 13 rules that cover the most common failure modes.
Rule 1: Loaders own all server-side data fetching
All data fetching for a route lives in its loader function.
Never fetch data in components using useEffect or client-side libraries
when a loader can serve it.
Loader data is typed via LoaderFunctionArgs and useLoaderData.
AI defaults to React Query or useEffect patterns it learned from SPAs. Remix loaders are simpler and eliminate the client-side waterfall entirely.
Rule 2: Actions own all mutations
All form submissions and data mutations go through action functions.
Do not use React state + fetch for mutations that modify server data.
Use the Form component or useFetcher for non-navigating mutations.
The action/loader pattern is Remix's core primitive. AI that bypasses it produces hybrid apps that lose Remix's progressive enhancement and optimistic UI benefits.
Rule 3: File-system routing is the only router
Routes are defined by file structure in the app/routes/ directory.
Do not create a manual router config or use React Router imperatively
except for programmatic navigation via useNavigate.
Nested routes use the Outlet component.
Rule 4: Session management lives in the server
All session data is stored server-side using createCookieSessionStorage
or createSessionStorage. Never store sensitive data in localStorage
or client-accessible cookies.
Rule 5: Error boundaries are co-located with routes
Every route that can fail exports an ErrorBoundary component.
Do not use a single top-level error boundary to catch all route errors.
Use CatchBoundary for HTTP errors (4xx, 5xx) and ErrorBoundary for
unexpected errors.
Rule 6: Meta and links are exported from route modules
Page metadata (title, description, og tags) is exported via the meta
function from the route module, not set imperatively in components.
Stylesheets and preloads use the links export.
Rule 7: Environment variables are server-only by default
All environment variables are server-only unless explicitly prefixed
for client exposure. Never access process.env in client-side code.
Use the loader to pass required config to the client as loader data.
Rule 8: Optimistic UI uses useFetcher
Optimistic updates use useFetcher with its state and formData.
Do not implement optimistic UI by managing local React state separately
from the server mutation — this creates sync bugs.
Rule 9: TypeScript types flow from loader to component
Use typeof loader as the type source for useLoaderData.
Define no duplicate type interfaces for loader return shapes.
All route types derive from the route module's exported types.
Rule 10: Defer only long-running non-critical data
Use defer() and Await only for data that is:
1. Non-critical for the initial render
2. Genuinely slow (>500ms)
Do not defer all data loading — this defeats the purpose of SSR.
Rule 11: Resource routes return non-HTML responses
Routes that return JSON, files, or webhooks export only a loader
or action, no default component. Name them with a dot prefix
(e.g., _api.webhook.ts) to distinguish from UI routes.
Rule 12: Progressive enhancement is the baseline
Forms must work without JavaScript enabled.
Use the Form component over fetch for all navigating mutations.
Enhance with JS via useFetcher and useNavigation.state,
but never require JS for core functionality.
Rule 13: Stacking order for CLAUDE.md in a Remix project
When generating any Remix code, check in this order:
1. Is there a loader that should own this data? Use it.
2. Is there an action that should own this mutation? Use it.
3. Is this a new route? Use file-system routing.
4. Is this a client-only concern? Only then use client state.
Do not skip steps 1-3 to reach step 4 faster.
The full CLAUDE.md block
Paste this into your Remix project's CLAUDE.md:
# Remix Project Rules
## Architecture
- All data fetching: loaders only (no useEffect data fetching)
- All mutations: actions only (no direct fetch in components)
- Routing: file-system only (app/routes/ directory)
- Session: server-side only (createCookieSessionStorage)
## Component Rules
- useLoaderData typed via typeof loader
- Optimistic UI: useFetcher only
- Error handling: per-route ErrorBoundary + CatchBoundary
- Meta/links: exported functions, not imperative DOM calls
## Environment
- process.env: server only
- Client config: passed through loader data
- Public env: must be explicitly opted in
## Progressive Enhancement
- All forms work without JS
- Form component for navigating mutations
- useFetcher for non-navigating mutations
- JS enhances, never required
## defer() Usage
- Only for non-critical data >500ms
- Never defer all route data
- Wrap with Await + ErrorBoundary
## Decision Order
1. Loader → 2. Action → 3. File route → 4. Client state
Why this matters more in Remix than other frameworks
Remix's conventions are load-bearing. The loader/action pattern isn't just a style guide — it's what enables:
- Automatic revalidation after mutations
- Progressive enhancement out of the box
- Parallel data loading without client waterfalls
- Error recovery at the route level
When AI breaks these conventions, it doesn't just produce bad code. It produces code that looks correct but silently opts out of everything that makes Remix worth using.
The CLAUDE.md file keeps every session — and every team member — inside the framework's mental model.
These 13 rules are part of a framework-specific CLAUDE.md series. The Cursor Rules Pack equivalent (50 production-tested rules across all stacks) is available at oliviacraftlat.gumroad.com/l/wyaeil.
Top comments (0)