· cursor / ai / coding

Cursor Rules Explained: Formats, Modes, and What to Avoid

Cursor rules bake your project conventions into the AI. Covers both file formats, all four activation modes, and the silent mistakes that break them.

By

1,828 words · 10 min read

Use the modern .cursor/rules/*.mdc format, not the legacy .cursorrules file. Put each concern in its own file. Keep files focused and scope them with globs so the AI only sees rules relevant to the code it’s touching.

Why Cursor rules matter

Without rules, Cursor’s AI knows nothing specific about your project. It applies general knowledge about TypeScript, React, or whatever language it detects — and its guesses are often off. It suggests patterns you banned last quarter, names variables in the wrong convention, or ignores the auth wrapper your entire API depends on.

With rules, the AI knows your constraints before it writes a line. It uses the withAuth wrapper without being told. It follows your naming conventions. It avoids the anti-patterns your team decided were off-limits after a production incident.

The difference isn’t subtle. A project with well-scoped rules gets output that fits in without editing. A project without rules gets output that requires a round-trip every time.

Who this is for

Developers already using Cursor who are getting generic output and suspect their rules aren’t working — or developers setting up a new project who want to get it right from day one. If you haven’t installed Cursor yet, rules are an advanced topic; read our Cursor 2026 review first, then come back once you’ve used it for a week.

The two formats

Cursor supports two rule formats, and they behave differently.

Legacy: .cursorrules

A single file at the project root with no frontmatter. Cursor still loads it — it is NOT silently ignored in Agent mode. But it has one limitation that matters: it’s a monolith. Every rule in it loads for every context, whether relevant or not. For new projects, don’t start here.

Modern: .cursor/rules/*.mdc

The .cursor/rules/*.mdc directory format is the current standard. A directory of scoped rule files, each with YAML frontmatter. Each file can target different contexts, different file types, or different activation modes. This is what you should use.

Critical detail: the extension must be .mdc. Plain .md files in .cursor/rules/ are silently ignored. Not loaded with a warning, not partially loaded — silently ignored. Name your files *.mdc or they don’t exist.

Four rule types

Each .mdc file has three frontmatter fields that control how Cursor decides to include it:

FieldTypeWhat it does
alwaysApplybooleanIf true, included in every Agent/Chat session
globsstringAttached when matching files are open or edited (Apply to Specific Files mode)
descriptionstringAI reads this to decide relevance in Apply Intelligently mode

These fields map to four rule types shown in Cursor’s UI:

Always Apply

---
alwaysApply: true
---

Included in every single Agent/Chat session. Use this for project-wide context — what the project is, what stack it uses, what the team’s non-negotiables are. Keep it short. If everything is always-applied, nothing is.

Apply to Specific Files

---
alwaysApply: false
globs: src/**/*.ts, src/**/*.tsx
---

Cursor attaches this rule automatically when you’re working with files that match the glob pattern. You don’t have to think about it. Good for framework conventions, linting preferences, or naming patterns that only matter in certain parts of the codebase.

globs accepts a comma-separated string of patterns. Standard glob syntax works: ** for any depth, *.ts for TypeScript files, src/api/** for a directory subtree.

Apply Intelligently

---
alwaysApply: false
description: "Use when working with database migrations or schema changes"
---

No globs, no alwaysApply. Cursor’s AI reads the description field and decides whether this rule is relevant to the current task. The AI judges this; you don’t control it directly. Write the description as a single, precise sentence about when this rule applies. Vague descriptions (“general coding standards”) get ignored or inconsistently applied.

Apply Manually

---
---

No metadata at all. This rule only loads when you explicitly include it with @ruleName in your prompt. Use this for rarely-needed context — migration playbooks, deployment checklists, or onboarding scripts that you want available but don’t want polluting every session.

Practical examples

Here are four .mdc files covering the most common use cases.

Project context (Always Apply)

---
alwaysApply: true
---

# project-context

This is a SaaS billing dashboard built with Next.js 14 (App Router), TypeScript, and Prisma on PostgreSQL.

**Non-negotiables:**
- All DB changes go through Prisma migrations — no raw SQL in application code
- Dates are always UTC in the DB; format for display at the UI layer
- Errors surface to the user via toast notifications, not console.log

**Repository layout:**
- `src/app` — Next.js App Router pages and layouts
- `src/components` — shared UI components
- `src/lib` — utilities, DB client, type definitions
- `prisma/` — schema and migrations

This rule gives the AI immediate context about what it’s working in. Every Agent session starts with this loaded.

Framework conventions (Apply to Specific Files)

---
alwaysApply: false
globs: src/**/*.tsx, src/**/*.ts
---

# typescript-conventions

**Imports:** Use `@/` path aliases — never relative paths from `src/`.

**Types:** Explicit return types on all exported functions. `interface` for object shapes, `type` for unions and intersections. No `any` without a comment explaining why it's unavoidable.

**Components:** One component per file. File name matches the exported component name in PascalCase. Props interface defined immediately above the component.

**State management:** `useState` for component-local state. Zustand for cross-component state. No Redux — it's not in this project.

This loads automatically when TypeScript files are open. The developer writes code, the AI already knows the conventions.

Anti-patterns to avoid (Apply Intelligently)

---
alwaysApply: false
description: "Use when asked to implement API endpoints, handle authentication, or work with user data"
---

# api-safety-rules

**Never do this:**
- Don't trust client-supplied IDs without verifying ownership against the authenticated user's session
- Don't log raw request bodies — they can contain secrets or PII
- Don't return detailed database error messages to the client — use generic messages and log the detail server-side
- Don't skip rate limiting on mutation endpoints

**Always do this:**
- Validate input at the route handler with Zod before passing to the service layer
- Use the `withAuth` wrapper from `src/lib/auth` — don't roll your own session check
- Return 404 (not 403) when a resource exists but the current user can't see it — don't confirm existence

The AI loads this when it detects the task involves API work. Security rules don’t pollute unrelated sessions.

Agent workflow (Apply Manually)

---
---

# deploy-checklist

Before deploying to production:

1. `pnpm prisma migrate status` — confirm all migrations applied in staging
2. `pnpm test:e2e` — end-to-end suite passes
3. Update `CHANGELOG.md` with the release summary
4. Tag the release: `git tag -a v<X.Y.Z> -m "release: <summary>"`

This rule is for the deploy workflow only. Load it with `@deploy-checklist` when executing a deployment.

You’d type @deploy-checklist run the deployment workflow in the Agent. Nothing else loads this by default.

Common mistakes

Using .md instead of .mdc. Cursor silently ignores .md files in .cursor/rules/. If a rule seems to do nothing, check the extension first.

Writing one giant .mdc file. A monolithic rules file defeats the purpose of the directory format. You can’t scope it. Everything loads everywhere. Split it: one file for project context, one per domain (API, UI, DB), one for each workflow you automate.

Vague description fields. “Coding standards and best practices” is not a description the AI can act on. Be specific: “Use when implementing REST endpoints or working with Prisma queries.” The AI uses this field to make a binary include/exclude decision.

Putting team opinions in alwaysApply. If you set everything to alwaysApply: true, you’re back to the monolith problem. Reserve Always Apply for the facts the AI needs in every session — project identity, stack, critical invariants. Put opinionated preferences in Apply to Specific Files or Apply Intelligently rules scoped to where they matter.

Conflicting rules with no resolution. If your global rule says “use camelCase for variables” and your backend rule says “match the database column naming,” the AI will pick one or oscillate. Make the more-specific rule win by being explicit: “Match the column name exactly when reading from or writing to the DB; camelCase elsewhere.”

Expecting rules to work in Cmd+K. They don’t. Per the Cursor docs, rules apply only to Agent and Chat modes. Cmd/Ctrl+K (Inline Edit) does not load your rules. Neither does Tab (autocomplete). If you’re getting inconsistent behavior, check which mode you’re in.

Writing instructions the AI can’t follow. “Write clean code” is not actionable. “Functions must not exceed 40 lines; extract helpers with descriptive names if they would” is actionable. The more specific the rule, the more reliably it’s applied.

Not version-controlling your rules. .cursor/rules/ lives in the repo. Commit it. Your team gets the same AI behavior. New joiners don’t have to reverse-engineer the conventions. Rules improve through code review just like any other file.

Letting rules go stale. A rule that describes last year’s architecture is worse than no rule — it actively misleads the AI. Treat rules like documentation: when you refactor a module, update the rule that mentions it. A wrong rule can be harder to debug than a missing one because the AI confidently does the wrong thing instead of falling back to its defaults.

Keeping files too long. There’s no hard character limit documented by Cursor. A useful working limit is around 200 lines per file; beyond that, focus tends to break down. If your TypeScript conventions file is growing past 200 lines, it probably contains several distinct concerns — component patterns, state management, API access — that each deserve their own scoped file.

Quick-start template

If you’re starting from scratch, here’s a minimal three-file setup:

.cursor/rules/
├── project-context.mdc     ← alwaysApply: true
├── code-conventions.mdc    ← globs: src/**/*.ts, src/**/*.tsx
└── api-safety.mdc          ← description: "when working with API or auth code"

project-context.mdc:

---
alwaysApply: true
---

# project-context

One paragraph: what this project is, what stack it runs on, and one or two things the AI should never do here.

code-conventions.mdc:

---
alwaysApply: false
globs: src/**/*.ts, src/**/*.tsx
---

# code-conventions

Bullet list of conventions specific to your TypeScript/framework setup. Three to five bullets max — the AI reads this every time it touches a `.ts` file.

api-safety.mdc:

---
alwaysApply: false
description: "Use when working with API routes, authentication, or data access"
---

# api-safety

Bullet list of the security rules your team cares most about. Input validation, auth checks, error handling.

Start with these three. Add files as you notice the AI getting things wrong in specific areas.


Working on AI-assisted development tooling? toolchew covers Cursor vs Claude Code, Cursor vs GitHub Copilot, and the rest of the AI dev-tool stack. Subscribe for practical coverage — tested tools, honest takes.