The gap between a generic Cursor setup and a well-tuned one isn't subtle. Without project-specific rules, Cursor treats every file the same — it doesn't know you're using the App Router, that your API routes live in a specific pattern, or that you never want any in production TypeScript.
CursorRules fix that. Here's a collection that actually works for modern Next.js, React, and TypeScript projects.
How CursorRules work in 2026
Cursor uses .cursorrules in your project root to inject persistent context into every AI request. These aren't prompts you type — they're standing instructions that shape all code generation throughout the session.
For projects where you also use Claude Code or other agents, maintain the canonical conventions in a CLAUDE.md file and reference the same patterns in .cursorrules. The two files serve different tools but cover the same ground — keeping them consistent prevents surprises. See our guide on writing CLAUDE.md for any project.
The rules below are organized by layer. Pick what applies to your stack.
Next.js App Router rules
These rules prevent the most common Next.js mistakes:
# Next.js App Router conventions
- Always use Server Components by default. Only add 'use client' when the component
needs browser APIs, event handlers, or React state/effects.
- Never fetch data in Client Components. Data fetching belongs in Server Components,
server actions, or Route Handlers.
- Use `next/image` for all images. Never use raw <img> tags.
- Use `next/link` for all internal navigation. Never use raw <a> tags for same-domain links.
- Route Handlers live in app/api/[route]/route.ts. Export named functions: GET, POST, PUT,
DELETE, PATCH.
- Server Actions use 'use server' directive and must be async functions.
- Environment variables prefixed with NEXT_PUBLIC_ are exposed to the browser.
Never put secrets in NEXT_PUBLIC_ variables.
- Use loading.tsx for route-level loading states. Use error.tsx for route-level
error boundaries.
- Metadata: export a `metadata` object or `generateMetadata` function from each page.
Never use <Head> tags.
React component rules
# React component conventions
- Component files use PascalCase. Utility files use camelCase.
- One component per file unless components are tightly coupled and not used elsewhere.
- Prefer composition over prop drilling. If you're passing props 3+ levels deep,
introduce context or restructure.
- Event handlers are named with 'handle' prefix: handleClick, handleSubmit, handleChange.
- Boolean props are named with 'is', 'has', or 'can' prefix: isLoading, hasError, canEdit.
- Never mutate state directly. Always create new objects/arrays.
- useEffect dependencies must be exhaustive. If you're tempted to omit a dependency,
restructure the code instead.
- Custom hooks go in src/hooks/. Name them useSomething.
- Avoid useEffect for derived state. Compute derived values directly during render.
TypeScript rules
# TypeScript conventions
- Never use `any`. Use `unknown` when the type is genuinely unknown, then narrow it.
- Never use non-null assertion `!` unless you can prove the value can't be null/undefined
at that point.
- Define types for all props. No implicit any in function parameters.
- Prefer `interface` for object shapes that may be extended. Use `type` for unions,
intersections, and primitives.
- Generic type parameters use descriptive names: TData, TError, TItem — not just T, U, V.
- API response types must be explicitly defined. Don't use `any` for fetch responses.
- Use Zod for runtime validation at API boundaries. Don't trust external data shapes.
- Use `satisfies` operator to validate objects against types without widening.
Tailwind CSS rules
# Tailwind conventions
- Use Tailwind utility classes. Never write custom CSS for things Tailwind can handle.
- Extract repeated patterns to components, not @apply directives.
- Responsive classes follow mobile-first order: base → sm → md → lg → xl → 2xl.
- Dark mode uses dark: prefix. Never manipulate colors with JavaScript for dark mode.
- Avoid arbitrary values ([px-37]) unless truly necessary. Many arbitrary values
signal a design decision is wrong.
- Color tokens: use semantic token names (text-foreground, bg-background) not
raw colors (text-gray-900).
File structure rules
# Project file structure
- src/app/ — App Router pages and layouts only
- src/components/ — reusable React components
- src/components/ui/ — Shadcn/primitive UI components (auto-generated, don't edit manually)
- src/lib/ — utility functions, API clients, type definitions
- src/hooks/ — custom React hooks
- src/types/ — shared TypeScript types
- API client files: src/lib/api/[resource].ts
- Never import from src/components/ui/ directly in page files — use higher-level components
Testing rules
# Testing conventions
- Test files co-located with source: ComponentName.test.tsx next to ComponentName.tsx
- Unit tests for utility functions in src/lib/
- Component tests use React Testing Library. Never test implementation details.
- Test user behavior, not component internals. Query by role, label, or text —
not by className or id.
- Mock network requests with MSW, not jest.mock on fetch.
- E2E tests with Playwright for critical user flows only.
Layering project-level and global rules
A .cursorrules in your project root is project-scoped. Rules in ~/.cursor/rules apply globally to all projects.
Recommended split:
Global (~/.cursor/rules):
- TypeScript strictness preferences
- Code style rules you want everywhere
- General patterns that apply across all your projects
Project (.cursorrules):
- Framework conventions specific to this project
- File structure rules
- Project-specific naming patterns and API conventions
In a monorepo, you can add .cursorrules files to specific package directories and Cursor applies them when you're working in that package. This lets you have different rules for your Next.js frontend and your Node.js backend in the same repo.
The highest-ROI rules to start with
If you're adding CursorRules for the first time, start with these two:
1. The Server/Client Component rule. This is the most common App Router mistake and the one that creates the hardest-to-debug errors. Getting Cursor to default to Server Components and only suggest 'use client' when genuinely needed saves significant debugging time.
2. TypeScript strictness. "Never use any" and "API responses must be typed" are the two rules that prevent the most future refactoring work. Cursor without these rules will happily generate any all over the place.
The file structure rules and testing conventions are worth adding once you have those two solid. The Tailwind rules help most on projects with design systems that differ from defaults.
For the vibe-coding workflow that these rules support, see our vibe coding prompting guide and the broader cursor AI prompting guide.



