Remix Cursor Rules: React Web Framework Guide
Cursor rules for Remix development covering nested routes, loader/action patterns, form handling, error boundaries, and server-side rendering with enhanced UX.

Overview
Remix is a full-stack React framework that emphasizes web fundamentals, nested routing, and progressive enhancement for superior user experiences. These cursor rules enforce strict loader/action data flow, robust form handling, and error boundary patterns to help AI assistants generate fast, resilient web applications. Whether you're handling complex mutations or optimizing server-side data loading, these rules ensure your application remains highly performant and accessible without compromising UX.
Note:
Enforces loader/action patterns, form handling conventions, error boundaries, and server-side rendering best practices.
Rules Configuration
---
description: Enforces best practices for Remix development, focusing on loader/action data flow, form handling, error boundaries, and progressive enhancement. Provides comprehensive guidelines for writing clean, resilient full-stack React applications with proper context.
globs: **/*.{js,jsx,ts,tsx}
---
# Remix Best Practices
You are an expert in Remix development and related web technologies.
You understand modern Remix development practices, architectural patterns, and the importance of providing complete context in code generation.
### Context-Aware Code Generation
- Provide route context including params, loader data types, and URL state
- Include relevant configs (remix.config.js, tsconfig.json) when scaffolding
- Generate complete loader/action signatures with typed params and responses
- Document route hierarchy and parent/child data dependencies
### Loader & Action Patterns
- Use loaders for GET requests to fetch and return data server-side
- Use actions for POST/PUT/DELETE mutations with form data
- Return typed JSON responses using json() utility from @remix-run/node
- Use useLoaderData and useActionData for type-safe access in components
- Implement resource routes for API endpoints and file downloads
### Form Handling & Progressive Enhancement
- Use `<Form>` over native `<form>` for JavaScript-enhanced submissions
- Validate and sanitize inputs inside action functions, not client-side
- Return validation errors from action and display via useActionData
- Use useNavigation for loading states and optimistic UI
- Support JavaScript-disabled clients with proper form fallbacks
### Routing & Nested Layouts
- Use file-based routing in /app/routes with flat or nested folder structure
- Leverage parent loaders to avoid redundant data fetching in child routes
- Use `<Outlet>` for nested layout rendering with persistent parent UI
- Implement layout routes with _layout convention for shared shells
### Error Boundaries & Best Practices
- Use ErrorBoundary for 500-level server errors per route
- Use CatchBoundary for thrown Response objects (404, 401)
- Provide fallback UI for each route segment to isolate failures
- Use TypeScript throughout for type-safe loader and action data
- Prefer server-side logic for data fetching; keep client for interactivity
- Add type-safe form validation with zod schemas in actions
- Include proper error handling in all loaders and actions
Installation
Create remix.mdc in your project's .cursor/rules/ directory and paste the configuration above. Cursor and Windsurf both read .cursor/rules/ — Copilot users place it in .github/copilot-instructions.md instead.
Examples
// app/routes/posts.$id.tsx — Loader and action with typed responses
import type { LoaderFunctionArgs, ActionFunctionArgs } from "@remix-run/node"
import { json } from "@remix-run/node"
import { useLoaderData, Form } from "@remix-run/react"
export async function loader({ params }: LoaderFunctionArgs) {
const post = await getPost(params.id)
if (!post) throw new Response("Not Found", { status: 404 })
return json({ post })
}
export async function action({ request, params }: ActionFunctionArgs) {
const formData = await request.formData()
const title = formData.get("title")
await updatePost(params.id, { title })
return json({ success: true })
}
export default function Post() {
const { post } = useLoaderData<typeof loader>()
return (
<Form method="post">
<input name="title" defaultValue={post.title} />
<button type="submit">Save</button>
</Form>
)
}
Related Resources
Related Articles
Docker Cursor Rules: Containerization & Deployment
Cursor rules for Docker covering multi-stage builds, layer caching, non-root users, health checks, .dockerignore, and docker-compose service orchestration.
SQL Cursor Rules: Database Query Optimization Guide
Cursor rules for SQL development covering query optimization, indexing strategies, window functions, CTEs, and database design patterns across major SQL dialects.
Node.js Cursor Rules: JavaScript Runtime
Cursor rules for Node.js covering ESM vs CommonJS, event loop, streams, Buffer, error handling, cluster/worker threads, file system, security, and package.json conventions.