Cursor's context injection system is the most powerful and flexible of any AI coding editor. Understanding how it works — and how to configure it correctly — is the difference between AI that fights your conventions and AI that follows them perfectly.
What Are Cursor Rules?
Cursor rules are Markdown files that inject persistent context into every AI request Cursor makes. Think of them as a permanent system prompt that runs before every conversation, every autocomplete suggestion, and every code generation.
When you describe your tech stack, coding conventions, and project constraints in a rules file, Cursor's AI applies them automatically — without you needing to repeat yourself on every prompt.
Two Rule Formats
Cursor supports two formats:
| Format | Location | Scope | Best for |
|---|---|---|---|
Legacy .cursorrules | Project root | Entire project | Simple projects, quick setup |
New MDC .cursor/rules/*.mdc | .cursor/rules/ directory | Per-file-pattern or always-apply | Large projects, per-context rules |
The legacy .cursorrules format still works but is considered deprecated. The .cursor/rules/ directory is the recommended approach.
The Legacy .cursorrules Format
Create a file called .cursorrules at the root of your project. It's plain Markdown:
markdown# Project: My Next.js App ## Tech Stack - Next.js 15 (App Router) - TypeScript 5.x (strict mode) - Tailwind CSS v4 - Drizzle ORM with PostgreSQL - Zod for validation ## Code Style - Use named exports (never default exports) - Prefer `const` arrow functions for components - All async functions must handle errors with try/catch - Never use `any` — use `unknown` or define a type ## File Structure - Components: `src/components/` - Server actions: `src/server/actions/` - DB queries: `src/server/db/queries/` - `@/` alias points to `src/` ## Important - We use Drizzle ORM — never suggest Prisma or other ORMs - TanStack Query for client-side data fetching (not SWR or React Query separately)
This gets injected into every Cursor AI request automatically.
The New MDC Format (.cursor/rules/)
Cursor's newer MDC format gives you more control. Each .mdc file has a YAML frontmatter section that controls when the rule applies.
File Structure
code.cursor/ └── rules/ ├── base.mdc # Always applied ├── frontend.mdc # Applied to frontend files ├── api.mdc # Applied to API files └── personal.mdc # Local overrides (gitignored)
MDC Frontmatter Options
yaml--- alwaysApply: true # Apply to every request description: "Frontend rules" # Used by the Agent for relevance detection globs: - "src/components/**" # Only apply when working in these paths - "src/app/**" ---
Rule Activation Types
The frontmatter fields control four activation modes:
- Always Apply (
alwaysApply: true) — injected into every chat session - Apply Intelligently (
alwaysApply: falsewithdescriptiononly) — Cursor's agent decides relevance based on the description - Apply to Specific Files (
globsspecified) — activates when file matches the glob pattern - Apply Manually (no frontmatter) — only loaded when you
@-mention the rule name in chat
Rule Precedence
Cursor follows this priority: Team Rules > Project Rules > User Rules. User Rules are configured in your Cursor settings and apply globally across all projects (Agent/Chat only, not inline autocomplete).
Example: Always-Applied Base Rules
markdown--- alwaysApply: true description: "Core project conventions" --- # Core Conventions - TypeScript strict mode — never use `any` - Named exports only - Error handling: all async functions must use try/catch - pnpm as the package manager (not npm or yarn)
Example: Path-Scoped Frontend Rules
markdown--- globs: - "apps/web/**" - "packages/ui/**" description: "Frontend-specific rules" --- # Frontend Rules (Next.js 15) - App Router only — never suggest Pages Router patterns - Use Server Components by default; only add `'use client'` when needed - Tailwind CSS v4 for all styling — no inline styles - shadcn/ui for primitives (never modify files in `components/ui/` directly)
When to Use .cursorrules vs. MDC
Use .cursorrules when:
- Your project is under 5 packages
- You want zero configuration overhead
- The rules apply uniformly across the entire project
Use MDC when:
- You have a monorepo with different conventions per package
- You want to create personal rules that don't get committed to Git
- You're building a rules library that others can selectively apply
Writing Effective Cursor Rules
1. Start with your tech stack header
The first thing in your rules should be a clear tech stack declaration. This prevents the AI from suggesting incompatible alternatives:
markdown## Tech Stack (Do Not Suggest Alternatives) - React 18 (not React 19 — we are NOT using useFormStatus or useOptimistic) - webpack 5 (not Vite) - Jest + React Testing Library (not Vitest or Cypress for unit tests) - Styled Components (not Tailwind or CSS Modules)
2. Specify exact import paths
markdown## Import Paths - UI components: `@/components/ui/Button`, `@/components/ui/Modal` - Hooks: `@/hooks/useAuth`, `@/hooks/useForm` - API client: `@/lib/api-client` - `@/` alias = `src/` directory
3. Give the AI examples of your patterns
Rather than describing patterns abstractly, show them:
markdown## Error Handling Pattern Use this pattern for all async operations: ```typescript try { const result = await someAsyncOperation() return { data: result, error: null } } catch (error) { logger.error('Operation failed', { error, context: 'componentName' }) return { data: null, error: error instanceof Error ? error.message : 'Unknown error' } }
code### 4. Anti-patterns gallery Explicitly forbidding common AI mistakes is more reliable than describing what you want: ```markdown ## Never Do These - Never use `dangerouslySetInnerHTML` — sanitize with DOMPurify if absolutely required - Never use `console.log` in production code — use our logger: `import { logger } from '@/lib/logger'` - Never store sensitive data in localStorage — use httpOnly cookies - Never import from `../../../` — always use path aliases - Never use `as any` to bypass type errors — fix the actual type issue
Cursor Rules for Common Stacks
Next.js 15 App Router
markdown## Next.js 15 Rules - App Router exclusively — no Pages Router (`_app.tsx`, `getServerSideProps`, etc.) - Server Components by default — add `'use client'` only when necessary (event handlers, browser APIs, useState/useEffect) - Server Actions for form submissions and mutations: `'use server'` directive at function top - `next/image` for all images (never `<img` tag) - `next/link` for all internal navigation - Route handlers in `app/api/` use `NextRequest`/`NextResponse` - Metadata: export `generateMetadata` function or static `metadata` object
React + Vite
markdown## Vite + React Rules - Vite for bundling — never suggest Next.js or CRA - React Router v6 with `createBrowserRouter` (not `BrowserRouter` component) - TanStack Query v5 for server state, Zustand for client state - Use `.tsx` for React files, `.ts` for utilities - Lazy load routes: `const Component = lazy(() => import('./Component'))`
Committing and Sharing Rules
Always commit your Cursor rules to version control so the whole team benefits:
bash# Commit legacy format git add .cursorrules && git commit -m "chore: add Cursor rules" # Commit MDC format git add .cursor/rules/ && git commit -m "chore: add Cursor MDC rules" # Gitignore personal rules only echo ".cursor/rules/personal.mdc" >> .gitignore
Tip: Use the Agent Rules Builder to generate a professionally structured
.cursorrulesfile for your specific tech stack.