Skip to contentNew: Does ChatGPT recommend your brand? Free 60-second AI visibility check →
By The DDH Team · Digital Dashboard Hub

Cursor Rules for Next.js (2026) Tutorial

By The DDH Team at Digital Dashboard HubUpdated

Stop writing AI prompts from scratch.

Tell us your business + your task + your model. We write the prompt — perfectly tuned for ChatGPT, Claude, Grok, Gemini, Midjourney, or any model. Plus 500+ pre-built prompts in your library.

14 days, no card. Cancel in 2 clicks.

Cursor's prompt-engineering surface evolved meaningfully in 2025. The legacy `.cursorrules` single-file format still works for backwards compatibility, but the modern path is per-directory `.cursor/rules/*.mdc` files. Each `.mdc` file is YAML frontmatter (name, description, globs, alwaysApply) followed by a markdown body — modular, scope-able, and committable to the repo so the whole team inherits the conventions.

Why this matters for Next.js 16 specifically: the App Router is full of conventions that an unfamiliar developer (or AI) will get wrong by default. Server Components vs Client Components, server actions vs API routes, cache directives, Suspense boundaries, the new Cache Components patterns — all of these are project-specific defaults you want Cursor to honor without you having to remind it every prompt.

This tutorial walks through 6 phases: (1) why rules matter for Cursor's context window; (2) Project Rules vs legacy `.cursorrules` — what changed and how to migrate; (3) Next.js 16 App Router-specific rules with a full `.mdc` example; (4) Tailwind + shadcn-specific rules; (5) database/auth/testing rules; (6) sharing rules across team via repo. Every example is a real working `.mdc` file you can paste into your project.

Sourced from cursor.com/docs/context/rules — the canonical doc. Read that doc before this one if you want the formal spec; read this one if you want the practical patterns. For a broader Cursor setup walkthrough, see migrate from Copilot to Cursor. For the related Claude Code rules pattern (CLAUDE.md / AGENTS.md), see Claude Code best practices 2026.

Digital Dashboard Hub

Writing good prompts for ONE AI is hard. Writing them for GPT-5, Claude, Gemini, Perplexity, Midjourney and 6 more is a full-time job. DDH's AI Prompt Builder writes once, runs everywhere — locked to your niche, voice, and brand tone.

Free 14 days, no card.

Cursor Rules formats: legacy vs current

Feature
Format
Location
Scope
Status
.cursorrules.cursorrulesRepo rootWhole repoLegacy, still works for backwards compat
Project Rules .mdc.cursor/rules/*.mdcAny directory in repoPer-directory via globsCurrent (2025+) — the recommended path
User RulesCursor Settings UIPer-user, all projectsAll projects on this machineCurrent — for personal preferences
@-mention rules.cursor/rules/*.mdcSelectively invoked via @Manual per-promptCurrent — for opt-in heavyweight rules

Source: https://cursor.com/docs/context/rules, verified 2026-06-21. Cursor recommends migrating from .cursorrules to .cursor/rules/*.mdc but doesn't deprecate the legacy format. Both can coexist in the same repo; modern format takes precedence on conflict. User Rules apply across all projects (good for personal conventions like 'always use semicolons') and don't conflict with project-scoped rules.

Phase 1: why rules matter (Cursor's context window + prompt engineering)

Cursor's AI surface has a limited context window — typically 200k tokens (the Claude Sonnet/Opus default). Every prompt you send includes: the file you're editing, related files you've @-referenced, conversation history, and... your rules. The rules are the bit you write once and Cursor injects every time.

Without rules, Cursor falls back to general programming knowledge — it'll write idiomatic Next.js, but 'idiomatic' for 2024 is different from 2026, and 'idiomatic' for the web is different from your team's specific conventions. Cursor doesn't know that your team prefers Zod over Yup, that you don't use `pages/` (you migrated to App Router), that your data layer is Supabase not Prisma, that your testing framework is Vitest not Jest. It guesses, often wrong.

Rules close that gap. A 200-line `.mdc` file describing your stack and conventions gets injected into every prompt, biasing Cursor's output toward what your team actually wants. The token cost is real (~500-2000 tokens per rule per prompt) but tiny relative to the win — Cursor's output goes from 'generally right' to 'team-specific right' on the first try, eliminating the back-and-forth iteration.

**Rules vs prompts:** prompts are the per-task instruction ('build me an X endpoint'). Rules are the always-on context ('we use App Router, Server Components by default, Supabase, Zod, shadcn, Vitest'). The combination — minimal prompt + comprehensive rules — produces 3-5x better output than either alone.

**Token-budget discipline.** Don't make rules sprawl. Each `.mdc` should be focused and scoped — 100-300 lines, with `globs` that target specific directories. Avoid one giant 1000-line rules file at the repo root with `alwaysApply: true` — it'll consume 8-10% of your context window on every prompt without delivering the per-task focus.


Phase 2: Project Rules vs legacy .cursorrules — migration path

If you already have a `.cursorrules` file, migrating is straightforward and worth doing. The benefits: per-directory targeting (rules for /app/ that don't apply to /api/), opt-in heavyweight rules (a 500-line testing rule that only loads when relevant), and the cleaner mental model of one rule = one concern.

**Migration step 1:** create the directory. `mkdir -p .cursor/rules` from your repo root.

**Migration step 2:** split your existing `.cursorrules` content by topic. Most legacy `.cursorrules` files mix concerns — stack conventions, file naming, error handling, testing, etc. Split each topic into its own `.mdc` file: `nextjs.mdc`, `tailwind.mdc`, `database.mdc`, `testing.mdc`.

**Migration step 3:** add YAML frontmatter to each. Minimal frontmatter:

``` --- name: nextjs-app-router description: Conventions for our Next.js 16 App Router code globs: - app/**/*.ts - app/**/*.tsx alwaysApply: true --- ```

**Migration step 4:** test by opening a file matching the glob, opening Composer, asking a question. Cursor's Composer pane shows the active rules in a small UI element — verify your rule is being applied.

**Migration step 5:** delete `.cursorrules` once you've verified the new structure works. Don't keep both — they'll add up in token cost without delivering benefit.

**Frontmatter fields.** `name` — short identifier. `description` — what this rule covers (Cursor uses this to decide when to load opt-in rules). `globs` — file patterns this rule applies to (glob syntax, supports `**`). `alwaysApply: true` — Cursor always loads this rule for files matching the globs; `false` (or omitted) — Cursor loads only when the user @-mentions the rule by name. Most rules should be `alwaysApply: true`; reserve `alwaysApply: false` for very specific cases (e.g., a 500-line testing rule you don't want loaded for production code work).


Phase 3: Next.js 16 App Router-specific rules (real .mdc file)

The App Router has a lot of conventions that need to be hardcoded into your AI's mental model. Server Components vs Client Components, server actions vs API routes, cache directives, Suspense, the new Cache Components patterns. Here's a real `.mdc` file we use in production Next.js 16 projects.

Save as `.cursor/rules/nextjs.mdc`:

``` --- name: nextjs-app-router description: Next.js 16 App Router conventions for this codebase globs: - app/**/*.ts - app/**/*.tsx - lib/**/*.ts alwaysApply: true --- # Next.js 16 App Router Conventions ## Routing - This project is fully on App Router. Do NOT create files in `pages/` — that directory doesn't exist in this codebase. - Route files: `app/[route]/page.tsx` for pages, `app/[route]/layout.tsx` for layouts, `app/[route]/loading.tsx` for Suspense fallbacks, `app/[route]/error.tsx` for error boundaries. - Dynamic routes: `app/[slug]/page.tsx`. Catch-all: `app/[...slug]/page.tsx`. - Route groups: `app/(marketing)/about/page.tsx` — parens for organizational grouping that doesn't appear in URL. ## Server vs Client Components - Default to Server Components. Only add `'use client'` directive when you actually need browser APIs, state, or event handlers. - If a component needs a hook (useState, useEffect, useRouter from 'next/navigation'), it must be a Client Component. - Server Components can render Client Components as children but NOT vice versa (don't import a Server Component into a Client Component). - Async Server Components are allowed and encouraged for data fetching: `export default async function Page() { const data = await fetchData(); return <UI data={data} />; }`. ## Data fetching - Prefer fetch in Server Components over client-side fetch + useEffect. - Use the Cache Components patterns (Next.js 16): the `use cache` directive at the top of a function, with `cacheLife(...)` and `cacheTag(...)` for tuning. - Do NOT use unstable_cache — it's deprecated in 16; migrate to `use cache` directive. - For mutations, use server actions ('use server' at top of file or function), not API routes. API routes only for webhooks, third-party callbacks, and public endpoints. ## Server actions - Server actions defined with 'use server' directive. - Always validate input with Zod before processing. - Always revalidatePath or revalidateTag after mutations that should reflect in UI. - Errors thrown in server actions surface to the form's error state — return validation errors as structured data, not exceptions. ## Caching - `use cache` directive at function top for cached server functions. - `cacheLife('default' | 'minutes' | 'hours' | 'days' | { stale, revalidate, expire })` to tune TTL. - `cacheTag('user:' + userId)` to enable targeted invalidation. - `updateTag('user:' + userId)` from server actions to invalidate. ## Loading + error UX - Always provide a `loading.tsx` in route segments with significant data fetching. - Always provide an `error.tsx` that's a Client Component (`'use client'`) with a reset button. - Use Suspense boundaries explicitly when you want to stream parts of a page independently. ## Anti-patterns - Do not use `getServerSideProps` or `getStaticProps` — those are Pages Router only. - Do not import server-only utilities (database client, env vars without NEXT_PUBLIC_) into Client Components — they'll bundle into the client JS. - Do not call `revalidatePath` from Client Components — it's a server-only API. - Do not use `next/router` — use `next/navigation` (App Router's router). ```

**Critical bits to call out.** The 'don't use unstable_cache' line catches a lot of AI tools that default to it from 2024 training data. The 'use cache directive' guidance steers Cursor toward the new Cache Components patterns. The Server-vs-Client Components rule prevents the common error of importing server code into Client Components.

Customize this file with your team's specific conventions: error message format, naming conventions, folder structure preferences.


Phase 4: Tailwind + shadcn-specific rules

Tailwind has near-infinite ways to write the same UI. Without rules, Cursor will pick one — sometimes the right one, often not your team's convention. Shadcn adds the layer of 'use these primitives, not raw Tailwind for buttons.' Save as `.cursor/rules/tailwind-shadcn.mdc`:

``` --- name: tailwind-shadcn description: Tailwind CSS and shadcn/ui conventions for this project globs: - app/**/*.tsx - components/**/*.tsx alwaysApply: true --- # Tailwind + shadcn/ui Conventions ## Component primitives - This project uses shadcn/ui. Use the existing primitives from `components/ui/` first; only fall back to raw Tailwind when no primitive exists. - Common primitives: Button, Input, Label, Textarea, Select, Checkbox, Switch, RadioGroup, Dialog, Sheet, Popover, Tooltip, Card, Table, Tabs, Badge, Alert, Sonner (toast). - To add a new primitive, run `npx shadcn@latest add <component>`. Do not hand-write components that shadcn provides. ## Spacing and sizing - Use Tailwind's spacing scale (gap-2, gap-4, gap-6, gap-8 — never gap-3, gap-5, etc.). - Default container max-width: max-w-screen-xl with mx-auto px-4 (md:px-6). - Vertical rhythm in cards: space-y-4 between sections within a card. ## Color and theming - Use CSS custom properties from globals.css (--background, --foreground, --primary, --muted, --accent, --destructive). Do NOT hardcode hex colors. - Dark mode is enabled via class strategy. Components automatically adapt via the CSS custom properties. - For brand-specific colors not in the design system, add them to tailwind.config.ts under `theme.extend.colors` rather than using arbitrary hex values inline. ## Composition patterns - Use `cn()` from `@/lib/utils` for conditional class merging. Do NOT concatenate strings or use clsx directly — `cn` wraps clsx with tailwind-merge to dedupe conflicting classes. - Variant-based components: use class-variance-authority (cva). Look at `components/ui/button.tsx` for the pattern. - Forwarded refs: wrap with React.forwardRef for components that need ref pass-through. ## Forms - Use react-hook-form + zod resolver (the shadcn/ui Form primitives wrap this pattern). - Form structure: <Form> → <FormField> → <FormItem> → <FormLabel> + <FormControl> + <FormMessage>. - Inline validation errors via <FormMessage />. ## Accessibility - Always provide aria-label on icon-only buttons. - Use shadcn's Dialog/Sheet/Popover — they handle focus trap and Esc-to-close correctly. - Form inputs always have a <Label> with `htmlFor` matching the input's `id`. ## Anti-patterns - Do not use Tailwind's @apply in CSS files — keep styles in JSX class strings. - Do not use inline style={{...}} except for dynamic values that can't be expressed in Tailwind (e.g., a calculated transform). - Do not import from 'tailwind-merge' or 'clsx' directly — use the project's cn() helper. - Do not write custom Button/Input/Modal components when shadcn provides them. ```


Phase 5: database, auth, and testing rules

The stack-specific rules. Save as `.cursor/rules/data-auth-testing.mdc`:

``` --- name: data-auth-testing description: Database, auth, and testing conventions for this project globs: - app/**/*.ts - app/**/*.tsx - lib/**/*.ts - **/*.test.ts - **/*.test.tsx alwaysApply: true --- # Database - Database: Supabase Postgres. Access via the typed client from `lib/supabase.ts`. - Schema lives in `supabase/migrations/`. Add new migrations with timestamps (e.g., `20260621_add_signups_index.sql`). - Row-level security (RLS) is enabled on every table. Always include the RLS policy in the migration when creating a new table. - Server-side queries use the service-role client. Client-side queries use the anon client and rely on RLS for authorization. - For complex queries, prefer raw SQL via `.rpc()` over chained query builders. # Auth - Auth: Supabase Auth with magic-link email flow. - Get the authenticated user on the server with `createServerClient()` from `lib/supabase/server.ts`. - Middleware protects /dashboard/* routes — see middleware.ts. - Client-side auth state via `useUser()` hook from `lib/supabase/client.ts`. - Always use the Supabase auth context, not custom JWT handling. # Validation - Zod schemas for all server action inputs. - Schemas live in `lib/schemas/*.ts` for shared types. - Type inference: `type X = z.infer<typeof xSchema>` for derived types — don't duplicate. # Error handling - Server actions return `{ ok: true, data } | { ok: false, error: string }`. Don't throw — return structured errors. - Server components: try/catch around data fetches. On error, throw and let error.tsx handle the boundary. - Client-side: surface errors via shadcn's <Sonner /> toasts using `toast.error('message')`. # Testing - Test framework: Vitest with @testing-library/react. - Test files colocated with the file under test: `Button.tsx` + `Button.test.tsx`. - Server actions tested with the test client setup in `vitest.setup.ts`. - E2E: Playwright (in `e2e/` directory), separate from Vitest unit tests. - Mocking: prefer real implementations (use Supabase's test schema). Mock only third-party APIs (Stripe, OpenAI). # What to test - Server actions: input validation, success path, error path, side effects (DB write). - Components: user-visible behavior (does clicking submit fire the action?). Not implementation details. - E2E: critical user journeys (signup, payment, core feature flow). Not every page. # Anti-patterns - Do not call `supabase.auth.getUser()` from Client Components — use `useUser()` hook. - Do not skip RLS on a 'we'll add it later' basis — every new table gets RLS in the same migration. - Do not use Jest, Mocha, or other test frameworks — this project is Vitest-only. - Do not test internal implementation details (function call counts, internal state) — test user-visible behavior. ```

**Why merge data/auth/testing into one file:** they share the same globs (all .ts/.tsx files) and are all 'how do we interact with the backend.' Splitting them into 3 files would triple the token-cost per prompt without clearer organization. Merge related concerns; split unrelated ones.


Phase 6: sharing rules across the team via repo

Project Rules are the per-directory `.mdc` files in `.cursor/rules/`. Commit them. Every team member who clones the repo and opens it in Cursor inherits the rules automatically — no manual setup.

**Gitignore strategy.** The default `.gitignore` from `npx create-next-app` doesn't mention Cursor. You want a project `.gitignore` that ignores most of `.cursor/` (local cache, chat history) but explicitly un-ignores `.cursor/rules/`:

``` # Cursor .cursor/* !.cursor/rules/ !.cursor/mcp.json ```

**Reviewing rules in PRs.** When a teammate adds or modifies a `.mdc` file, treat it like any other code change — review in the PR. Bad rules drift over time; PR review catches the 'this rule contradicts the actual codebase pattern' issues early.

**The 'one source of truth' principle.** If you also use Claude Code (with `AGENTS.md`/`CLAUDE.md`), don't write the same conventions twice. Pick one canonical file (often `AGENTS.md` at repo root) and have your `.cursor/rules/` files reference it: 'Always follow conventions in AGENTS.md.' Keeps the conventions DRY and prevents drift between tools.

**Rule documentation in the repo README.** Add a 'For AI tools' section to your README that lists the active Cursor rules, where they live, and how to update them. Helps new team members understand the AI conventions before they start prompting.

**Periodic rule review.** Schedule a 30-minute review every quarter: which rules fire often, which are stale, which patterns the team has adopted that aren't yet rules? The codebase evolves; rules should too. Stale rules that contradict current code are worse than no rules — they pollute every prompt with outdated context.

**Onboarding loop.** For a new team member: (1) clone repo, (2) open in Cursor, (3) read the rules in `.cursor/rules/` (literally — they're markdown, very readable), (4) start with a small task. The rules give them an instant onramp to the team's conventions without requiring a pairing session for every prompt.


Rule patterns that work: opt-in heavyweight rules

Sometimes a rule is too large or too specific to apply to every file. Example: a 500-line rule on 'how we write internal CLI tools' that only matters when working in `scripts/`. Solution: opt-in rules.

**Opt-in rule pattern.** Set `alwaysApply: false` in frontmatter. The rule loads only when the user @-mentions it in a prompt: '@cli-conventions write a script to do X.' Cursor injects the rule for that prompt only.

**Example opt-in rule.** Save as `.cursor/rules/cli-scripts.mdc`:

``` --- name: cli-scripts description: Conventions for internal CLI scripts in scripts/ globs: - scripts/**/*.ts alwaysApply: false --- # Internal CLI Script Conventions - Use commander.js for CLI argument parsing. - Use ora for spinners on long-running operations. - Use chalk for colored output: green for success, yellow for warning, red for error. - Use zx for shell commands instead of child_process. - Scripts should be runnable via `tsx scripts/<name>.ts`. - Document the CLI flags in a JSDoc comment at the top of the file. - Exit codes: 0 = success, 1 = expected error, 2 = unexpected error. ```

**When to use opt-in vs always-apply.** Always-apply for conventions that affect 50%+ of files in the matching globs. Opt-in for conventions that affect <10% of files OR conventions that need full context (the 500-line testing playbook, for example).

**Hybrid pattern.** A short always-apply rule that says 'for testing concerns, see @testing-deep' (opt-in). Default behavior follows the short version; deep work pulls the full rule. Best of both worlds — small per-prompt token cost in normal flow, full context when needed.


Common rule mistakes that hurt output quality

**Mistake 1: rules that contradict the actual codebase.** A rule says 'use Yup for validation' but the codebase has 50 Zod schemas. Cursor will see the contradiction and pick at random — usually the wrong one. Audit rules quarterly against the actual code.

**Mistake 2: too-vague rules.** 'Write clean code' produces no behavior change. 'Use snake_case for database columns, camelCase for TypeScript variables' produces an immediately visible behavior change. Rules need to be specific and operational.

**Mistake 3: rules without examples.** A rule that says 'use the form pattern' is weaker than a rule that says 'use the form pattern like this: <Form>...example...</Form>'. Concrete examples in rules anchor Cursor's output meaningfully better than abstract guidelines.

**Mistake 4: huge single-file rules.** A 2000-line `.cursorrules` at the repo root with `alwaysApply: true` consumes 8-10% of every prompt's context window. Split into scoped files. Make most rules scoped to specific globs.

**Mistake 5: not updating rules when the stack changes.** You migrate from Prisma to Drizzle. Cursor keeps generating Prisma code because the rules still say Prisma. The rules update is part of the migration PR.

**Mistake 6: rules that prohibit without explaining.** 'Do not use X' is OK; 'Do not use X because we hit Y bug; use Z instead' is much better. The 'why' helps Cursor handle adjacent cases — it'll avoid not just X but also X-like things.

**Mistake 7: rules that conflict between files.** `.cursor/rules/styling.mdc` says 'use Tailwind v4 features.' `.cursor/rules/legacy.mdc` says 'support Tailwind v3 for the legacy/ directory.' Both with always-apply. Cursor sees both and gets confused. Scope each rule to its directory via globs.


Sharing rules across multiple AI tools (Cursor + Claude Code + Copilot)

Most teams in 2026 run multiple AI coding tools — Cursor for IDE work, Claude Code for terminal/agent work, sometimes Copilot for ambient completion. Each tool has its own rules format: Cursor's `.cursor/rules/*.mdc`, Claude Code's `CLAUDE.md` or `AGENTS.md`, Copilot's `.github/copilot-instructions.md`. Three formats, same intent.

**The DRY pattern that works:** maintain one canonical conventions file at repo root — `AGENTS.md` is the increasingly common choice — and have each tool's specific rules reference it. `.cursor/rules/main.mdc` becomes a thin wrapper:

``` --- name: main description: Project conventions (see AGENTS.md for full list) globs: - '**/*.ts' - '**/*.tsx' alwaysApply: true --- # Project Conventions Always read AGENTS.md at the repo root before making any change. It contains the canonical conventions for this codebase. Key points for quick reference: - Stack: Next.js 16 App Router + TypeScript + Tailwind + shadcn/ui + Supabase + Stripe + Vitest. - Default to Server Components; mark Client Components with 'use client'. - Use cn() for class merging, not raw clsx. - All server action inputs validated with Zod. - All new tables get RLS in the same migration. For specifics, see AGENTS.md. ```

**Why this works.** Cursor injects the short rule (small token cost) and trusts that Cursor's Composer / Chat will read `AGENTS.md` when it needs deeper context. Claude Code reads `AGENTS.md` natively. Copilot's per-repo instructions file can also point to `AGENTS.md`.

**The single conversation between tools.** With one canonical source, you update conventions in one place when the stack evolves. No three-way drift, no tool-specific conventions that contradict each other.

**Edge case: tool-specific behaviors.** Some conventions are genuinely tool-specific — Cursor's Composer-vs-Chat usage patterns, Claude Code's hook configurations. Those go in tool-specific files (`.cursor/rules/composer.mdc`, `CLAUDE.md`). Shared conventions go in `AGENTS.md`. Decide per rule which bucket it belongs to.

Cursor Rules for Next.js setup in 6 steps

  1. 1

    Create the .cursor/rules/ directory and gitignore config

    `mkdir -p .cursor/rules`. Update .gitignore to ignore `.cursor/*` but un-ignore `.cursor/rules/` and `.cursor/mcp.json` (commit those, ignore everything else).

  2. 2

    Create nextjs.mdc with App Router conventions

    Use the full .mdc example above. Cover routing, Server vs Client Components, data fetching, server actions, caching (use cache directive, cacheLife, cacheTag), loading + error UX, and anti-patterns (no Pages Router, no unstable_cache). Globs: app/**/*.ts(x), lib/**/*.ts. alwaysApply: true.

  3. 3

    Create tailwind-shadcn.mdc with UI conventions

    Cover shadcn primitives (use them first, fall back to raw Tailwind only when no primitive exists), spacing/sizing conventions, theming via CSS custom properties, cn() for class merging, react-hook-form + Zod for forms, accessibility patterns. Globs: app/**/*.tsx, components/**/*.tsx.

    → Open the Code prompt builder (Cursor-tuned)
  4. 4

    Create data-auth-testing.mdc with backend conventions

    Cover Supabase schema/migrations/RLS, magic-link auth flow, Zod validation, server-action error pattern ({ok, error} returns), Vitest + Playwright testing patterns. Globs: app/**/*.ts(x), lib/**/*.ts, **/*.test.ts(x).

  5. 5

    (Optional) Create opt-in rules for specialized contexts

    For conventions that only apply to specific contexts (CLI scripts, mobile UI, internal admin tooling), create .mdc files with `alwaysApply: false`. Users invoke them per-prompt via @-mention. Reduces per-prompt token cost in normal flow.

  6. 6

    Commit, share, and review quarterly

    Commit .cursor/rules/ to repo. Add an 'AI tools' section to README pointing at the rules. Review quarterly: which rules fire often, which are stale, which patterns the team adopted that aren't yet rules. Update rules in the same PR as stack migrations to prevent drift.

Frequently Asked Questions

What's the difference between .cursorrules and .cursor/rules/ in 2026?

.cursorrules is the legacy single-file format (repo root, one file, whole-repo scope). .cursor/rules/*.mdc is the current format (per-directory .mdc files with YAML frontmatter — name, description, globs, alwaysApply). Both work; modern format is recommended. The .mdc format enables per-directory targeting, opt-in heavyweight rules, and cleaner separation of concerns. Source: cursor.com/docs/context/rules.

How do I migrate from .cursorrules to .cursor/rules/?

Five steps: (1) mkdir -p .cursor/rules; (2) split your existing .cursorrules content by topic (nextjs, tailwind, database, testing); (3) add YAML frontmatter to each .mdc (name, description, globs, alwaysApply); (4) test by opening a matching file in Composer and verifying the rule appears in the active-rules UI; (5) delete .cursorrules once verified. Don't keep both — they'll add up in token cost without delivering benefit.

What should a Cursor Rule for Next.js 16 cover?

App Router conventions (no pages/, route file structure, dynamic routes, route groups), Server vs Client Components (default to Server, 'use client' only when needed), data fetching patterns (fetch in Server Components, use cache directive with cacheLife/cacheTag for Cache Components), server actions (Zod validation, revalidatePath after mutations, structured error returns), loading + error UX (loading.tsx, error.tsx with Client Component reset), and anti-patterns (no getServerSideProps, no unstable_cache, no next/router — use next/navigation).

What does YAML frontmatter look like in a .mdc Cursor rule?

Four common fields. `name`: short identifier (e.g., 'nextjs-app-router'). `description`: what this rule covers (Cursor uses this for opt-in matching). `globs`: file patterns this rule applies to (glob syntax, supports **). `alwaysApply: true`: Cursor always loads the rule for files matching globs; `false` means the rule loads only when the user @-mentions it in a prompt. Most rules should be alwaysApply: true; reserve false for very long opt-in rules.

Can multiple .mdc rules apply to the same file?

Yes — Cursor applies all rules whose globs match the current file. Multiple rules with overlapping globs all inject their content into the prompt. The risk: if two rules contradict (one says 'use Yup', another says 'use Zod'), Cursor sees both and behavior is unpredictable. Audit rules for contradictions during quarterly review; scope rules to specific globs to minimize overlap.

Should I commit .cursor/rules/ to my repo?

Yes — that's the whole point. Commit .cursor/rules/ so team members inherit conventions automatically when they clone and open the repo in Cursor. Use a .gitignore pattern that excludes most of .cursor/ (local cache, chat history) but un-ignores .cursor/rules/ and .cursor/mcp.json. Review .mdc file changes in PRs like any other code change.

How do I share rules across Cursor + Claude Code + Copilot?

Maintain one canonical conventions file at repo root — AGENTS.md is the increasingly common choice. Cursor's .cursor/rules/main.mdc, Claude Code's CLAUDE.md, and Copilot's .github/copilot-instructions.md all reference 'see AGENTS.md for canonical conventions.' Tool-specific rules (Cursor's Composer-vs-Chat usage, Claude Code's hook configs) stay in tool-specific files. Shared conventions live in AGENTS.md to prevent three-way drift.

What are common mistakes with Cursor Rules?

Seven common ones: (1) rules that contradict the actual codebase (audit quarterly); (2) too-vague rules ('write clean code') that produce no behavior change; (3) rules without examples (abstract guidelines underperform concrete code samples); (4) huge always-apply rules that consume 8-10% of context window on every prompt; (5) not updating rules when the stack changes; (6) prohibit-without-explaining rules — 'do not use X' is weaker than 'do not use X because we hit Y bug; use Z instead'; (7) rules that conflict between .mdc files (scope each rule to its directory via globs).

Rules set the floor. Prompts set the ceiling.

Cursor Rules eliminate the back-and-forth on conventions. Prompts determine whether the output is generic or great. Our AI Prompt Generator writes Cursor-ready prompts that respect your rules and ship at your team's quality bar. 14-day free trial, no card.

Browse all prompt tools →