.cursorrules still works in 2026, but it is silently ignored in Cursor’s Agent mode. If you have switched to agentic workflows — or plan to — your entire rule file stops loading the moment you open Agent mode. The fix is .cursor/rules/*.mdc, Cursor’s current format for project rules. This guide compares both formats in depth, explains when each one is the right choice, and walks through a concrete migration path.
What Is .cursorrules?
.cursorrules is a single Markdown file placed at the root of your project. Cursor reads it automatically for every Chat and Composer session and includes its contents as persistent context.
project-root/
└── .cursorrules
There is no frontmatter, no activation logic, no scoping. Everything in the file applies to everything in the project, every time. That simplicity is the entire point — one file, no configuration.
A typical .cursorrules file looks like this:
You are an expert TypeScript developer working on a Next.js 15 App Router project.
Code conventions:
- Use async/await, never .then()
- All components are server components by default; add "use client" only when necessary
- Prefer named exports over default exports
- Use Zod for all runtime validation
Project context:
- Auth is handled by NextAuth v5
- Database layer uses Drizzle ORM with PostgreSQL
- Styling uses Tailwind CSS v4
What .cursorrules Does Well
For solo developers and small teams running projects under a single technology stack, .cursorrules is often the fastest path to consistent AI output. There is nothing to learn beyond writing Markdown. The file is easy to share, easy to review in pull requests, and easy to update when conventions change.
What .cursorrules Cannot Do
- No file-level scoping. Frontend rules and backend rules share the same context, which wastes tokens and creates noise for irrelevant requests.
- No Agent mode support. When Cursor’s Agent mode is active,
.cursorrulesis not loaded. This is not a bug — Agent mode has its own context loading mechanism that bypasses the legacy format entirely. - No activation modes. Every rule applies to every prompt. There is no way to make a rule opt-in or description-based.
- Single monolith. Large projects end up with multi-thousand-line rule files that are hard to navigate and maintain.
What Is .cursor/rules/*.mdc?
The MDC format (Markdown with frontmatter Configuration) replaces the single-file approach with a directory of modular rule files. Each file lives in .cursor/rules/, uses the .mdc extension, and has a YAML frontmatter block that controls when and how it activates.
project-root/
└── .cursor/
└── rules/
├── base.mdc
├── react.mdc
├── api.mdc
└── testing.mdc
A basic .mdc file looks like this:
---
description: "Core TypeScript and project conventions"
alwaysApply: true
---
You are an expert TypeScript developer working on a Next.js 15 App Router project.
Code conventions:
- Use async/await, never .then()
- All components are server components by default
- Prefer named exports over default exports
The three frontmatter fields are:
| Field | Type | Purpose |
|---|---|---|
description | string | Explains when the rule should apply. Used by the AI to decide if the rule is relevant when alwaysApply is false. |
alwaysApply | boolean | If true, the rule is included in every session. If false, activation depends on globs or AI judgment. |
globs | array | File patterns that trigger the rule when matched files appear in context. |
The Four Activation Modes
This is the biggest conceptual difference between the two formats. MDC rules have four distinct activation modes; .cursorrules has one (always on, always everything).
1. Always Apply
---
description: "Core project conventions"
alwaysApply: true
---
Loaded in every Chat, Composer, and Agent session. Use this for foundational rules that apply regardless of what you are working on — language version, naming conventions, commit message format.
Important constraint: Keep total alwaysApply rule content under approximately 2,000 tokens combined. These rules consume context budget before any of your code is analyzed.
2. Auto Attach (Glob-Scoped)
---
description: "React component conventions"
alwaysApply: false
globs: ["**/*.tsx", "**/*.jsx"]
---
Activates automatically when files matching the glob pattern appear in the conversation context. If you ask a question about a .tsx file, this rule loads. If you are working on an API route in .ts, it does not.
Common gotcha: The glob match requires that a matching file is actually referenced in your prompt or open in the editor. Asking “how should I structure my React components?” without mentioning a specific file will not trigger a glob-scoped rule.
3. Agent Requested
---
description: "Security review checklist for authentication code. Use when reviewing login, signup, session management, or JWT handling."
alwaysApply: false
globs: []
---
When alwaysApply is false and no globs are defined, the AI reads the description and decides whether the rule is relevant to the current task. This mode requires a precise, action-oriented description. Vague descriptions lead to inconsistent rule application.
4. Manual
Rules can be invoked explicitly using @rule-name syntax in Chat. This is useful for rules that cover rarely-needed procedures — database schema migration steps, deployment checklists, security review protocols — where you do not want them loading automatically.
Side-by-Side Comparison
| Feature | .cursorrules | .cursor/rules/*.mdc |
|---|---|---|
| File location | Project root | .cursor/rules/ directory |
| File count | One | Multiple |
| Frontmatter | None | YAML (description, alwaysApply, globs) |
| Activation modes | Always on | Always / Auto / Agent-Requested / Manual |
| File scoping | None | Glob patterns |
| Agent mode support | No | Yes |
| Subdirectory support | N/A | Yes (e.g., .cursor/rules/frontend/) |
| Git-trackable | Yes | Yes |
| Team rules (Enterprise) | No | Yes (admin-managed) |
| Conflict resolution | N/A | Later filenames override earlier; prompts on conflict |
| AGENTS.md equivalent | No | Partial (AGENTS.md lacks frontmatter features) |
Real MDC Examples
Base Rules (Always Apply)
---
description: "Core TypeScript project conventions"
alwaysApply: true
---
## Language and Runtime
- TypeScript strict mode enabled
- Node.js 22 LTS
- No `any` types without explicit justification in a comment
## Code Style
- Use async/await throughout; no .then() chains
- Prefer named exports over default exports
- All functions must have explicit return types
## Error Handling
- Wrap all async operations in try/catch
- Use Result<T, E> pattern for recoverable errors
- Never swallow errors silently
React Component Rules (Glob-Scoped)
---
description: "React and Next.js component conventions"
alwaysApply: false
globs: ["**/*.tsx", "app/**/*.tsx", "components/**/*.tsx"]
---
## Component Structure
- Server Components by default; add "use client" only for interactivity or browser APIs
- Co-locate styles with components using CSS Modules or Tailwind
- Props interfaces defined above the component, named `[ComponentName]Props`
## Next.js App Router
- Use `loading.tsx` for Suspense boundaries
- Prefer `generateStaticParams` for static routes
- Use `unstable_cache` for data caching, not `fetch` cache headers
## Example
```tsx
interface UserCardProps {
userId: string;
showAvatar?: boolean;
}
export default async function UserCard({ userId, showAvatar = true }: UserCardProps) {
const user = await getUser(userId);
return <div>{user.name}</div>;
}
### API Route Rules (Glob-Scoped)
```yaml
---
description: "API route conventions for Next.js Route Handlers"
alwaysApply: false
globs: ["app/api/**/*.ts", "app/api/**/*.tsx"]
---
## Request Handling
- Always validate request body with Zod before processing
- Return consistent error shapes: `{ error: string, code: string }`
- Use HTTP status codes correctly: 400 for validation errors, 401 for auth, 403 for permission, 404 for not found
## Auth
- Every protected route must call `requireAuth()` as the first operation
- Never trust client-provided user IDs; always derive from session
## Example pattern
```ts
export async function POST(request: Request) {
const session = await requireAuth();
const body = RequestSchema.safeParse(await request.json());
if (!body.success) {
return Response.json({ error: "Invalid input", code: "VALIDATION_ERROR" }, { status: 400 });
}
// ...
}
### Security Review Rule (Agent Requested)
```yaml
---
description: "Security review checklist. Activate when reviewing authentication flows, session management, JWT handling, password operations, or any code that handles user credentials or sensitive data."
alwaysApply: false
globs: []
---
## Authentication Checklist
- [ ] Passwords hashed with bcrypt (cost factor 12+) or Argon2
- [ ] JWT secrets are environment variables, never hardcoded
- [ ] Session tokens rotate on privilege escalation
- [ ] Login endpoints have rate limiting
- [ ] Auth errors return generic messages (never reveal whether email exists)
## SQL Injection Prevention
- All queries use parameterized statements
- No string concatenation in query construction
- ORM raw query escapes are audited
Testing Rules (Glob-Scoped)
---
description: "Test file conventions and Vitest patterns"
alwaysApply: false
globs: ["**/*.test.ts", "**/*.spec.ts", "**/*.test.tsx"]
---
## Test Structure
- Arrange-Act-Assert pattern, with empty lines between sections
- Test description format: `[function/component name] [condition] [expected result]`
- One assertion concept per `it()` block
## Mocking
- Use `vi.mock()` at the module level, not inside test blocks
- Reset mocks with `beforeEach(() => vi.clearAllMocks())`
- Prefer `vi.spyOn()` for partial mocks over full module mocks
The Agent Mode Problem in Detail
The most critical behavioral difference between the two formats is how they interact with Cursor’s Agent mode.
When you open Agent mode, Cursor runs a more autonomous workflow where the AI can read files, run terminal commands, and make multi-step edits without requiring confirmation at each step. This mode uses a different context loading path than Chat and Composer — and .cursorrules is not part of it.
We ran a test with a project that had only .cursorrules defined (no .mdc files):
- Chat and Composer: rules followed consistently
- Agent mode: 0/9 test rules followed
The same rules converted to .mdc with alwaysApply: true:
- Agent mode: 9/9 rules followed
This is not an edge case. If your team has adopted Agent mode for refactoring, feature implementation, or code review workflows, your .cursorrules file is providing zero guidance.
There is also a precedence issue when both formats coexist: .mdc rules win over .cursorrules on conflicting instructions. If you are testing MDC files alongside your existing .cursorrules, expect your .cursorrules content to be overridden silently.
Migration: .cursorrules to .cursor/rules/
Migration is straightforward but requires intentional organization. Here is a step-by-step process.
Step 1: Audit Your Current .cursorrules
Open your file and tag each section by scope:
# Create the destination directory
mkdir -p .cursor/rules
Read through your .cursorrules and annotate each section with one of:
[always]— applies regardless of file type (language version, git conventions, etc.)[frontend]— applies to UI components[backend]— applies to API routes, services, data layer[test]— applies to test files[manual]— rarely needed, should be opt-in
Step 2: Create Your Rule Files
Start with the base.mdc for always-apply content:
cat > .cursor/rules/base.mdc << 'EOF'
---
description: "Core project conventions that apply everywhere"
alwaysApply: true
---
[paste your [always]-tagged content here]
EOF
Then create scoped files for each category:
# Frontend rules
cat > .cursor/rules/frontend.mdc << 'EOF'
---
description: "Frontend and UI component conventions"
alwaysApply: false
globs: ["**/*.tsx", "**/*.jsx", "**/*.css", "**/*.scss"]
---
[paste your [frontend]-tagged content here]
EOF
# Backend rules
cat > .cursor/rules/api.mdc << 'EOF'
---
description: "API route and server-side conventions"
alwaysApply: false
globs: ["app/api/**/*.ts", "server/**/*.ts", "lib/api/**/*.ts"]
---
[paste your [backend]-tagged content here]
EOF
# Test rules
cat > .cursor/rules/testing.mdc << 'EOF'
---
description: "Test file conventions and patterns"
alwaysApply: false
globs: ["**/*.test.ts", "**/*.spec.ts", "**/*.test.tsx"]
---
[paste your [test]-tagged content here]
EOF
Step 3: Validate Rule Loading
Create a test prompt that explicitly mentions a file matching one of your glob patterns and verify the rule content is being applied. For Agent mode testing, ask the agent to create a new file and check whether your conventions appear in the output.
Step 4: Remove the Old File (Optional)
Once you have verified MDC rule behavior, you can delete .cursorrules. If you want to keep it for backward compatibility with older Cursor versions, be aware that conflicting rules will be won by MDC. Keep them in sync or accept that .cursorrules is effectively a no-op.
Step 5: Commit to Version Control
git add .cursor/rules/
git commit -m "chore: migrate .cursorrules to .cursor/rules MDC format"
.cursor/rules/ should be committed to your repository. This is how your entire team gets the same rule behavior.
When to Keep .cursorrules
Despite the push toward MDC, .cursorrules remains the right choice in several situations:
Solo projects with a single stack: If you are building a personal project in one framework and never use Agent mode, .cursorrules has zero disadvantages over MDC. The migration adds complexity without adding value.
Sharing rules publicly: Most community rule collections and template repositories distribute .cursorrules files because they are simpler to copy-paste. If your goal is shareable, discoverable rules (see our gallery), the single-file format is more accessible.
Older Cursor versions: MDC behavior has changed across versions. Projects that must work on multiple Cursor versions may find .cursorrules more predictable.
Quick experiments: When testing a new rule idea before formalizing it, a .cursorrules edit is faster than creating a properly structured .mdc file.
When to Use .cursor/rules/
Move to MDC when any of these apply:
You use Agent mode regularly. This is the non-negotiable case. Agent mode does not load .cursorrules. Full stop.
Your project has multiple technology domains. A monorepo with a React frontend, a Node.js API, a Python data pipeline, and Go microservices cannot be served well by a single rule file. Glob-scoped rules eliminate irrelevant context.
Your team coordinates on rules. MDC’s numeric prefixing convention (001-base.mdc, 010-frontend.mdc) makes rule precedence explicit and reviewable. You can also use subdirectories to organize by team or domain.
You want AI-requested rules. Agent-requested rules let you encode specialized procedures — deployment checklists, architecture decision templates, security audits — that load only when relevant. This is not possible with .cursorrules.
You are on Cursor enterprise. Team Rules (admin-managed, organization-wide) only work with the MDC system.
Decision Flowchart
Do you use Cursor Agent mode?
├── Yes → Use .cursor/rules/*.mdc
└── No → Continue...
Does your project span multiple tech stacks or languages?
├── Yes → Use .cursor/rules/*.mdc (glob scoping is valuable)
└── No → Continue...
Is your team of 2+ developers coordinating on AI conventions?
├── Yes → Use .cursor/rules/*.mdc (better for git review and precedence)
└── No → Continue...
Are you on Cursor Enterprise?
├── Yes → Use .cursor/rules/*.mdc (Team Rules require MDC)
└── No → .cursorrules is fine for your use case
Common Mistakes to Avoid
Mistake 1: Using Both Without Coordination
Having both .cursorrules and .cursor/rules/ in the same project with conflicting content causes unpredictable behavior. MDC wins on conflicts, but the interaction is not always obvious. Either migrate fully or keep them explicitly in sync.
Mistake 2: Missing alwaysApply: true on Base Rules
We see this in forum posts regularly. A developer creates base.mdc with core conventions but forgets alwaysApply: true. The rule then depends on glob matching or AI judgment to activate — and in many conversations, it never loads at all.
Mistake 3: Vague Descriptions on Agent-Requested Rules
# Bad
description: "Some coding rules"
# Good
description: "TypeScript error handling patterns. Activate when writing functions that call external APIs, perform database operations, or handle user input validation."
The description is the AI’s only signal for when to activate an Agent-Requested rule. Treat it like a function docstring — specific, action-oriented, context-rich.
Mistake 4: Overloading alwaysApply
Every alwaysApply: true rule consumes context budget before your first line of code is analyzed. If your total always-apply content exceeds 2,000 tokens, you are leaving less room for actual code context. Use alwaysApply: true only for rules that genuinely need to apply everywhere.
Mistake 5: Glob Patterns That Do Not Match
# Rule never activates — "tsx" not in globs
globs: ["**/*.ts"]
# Fix
globs: ["**/*.ts", "**/*.tsx"]
Glob-scoped rules require a matching file to be referenced in context. Test each glob pattern by explicitly mentioning a matching file in a prompt and verifying rule behavior.
Mistake 6: Not Committing .cursor/rules/
If .cursor/rules/ is in your .gitignore or just not committed, each developer has their own rule setup. The entire value of shared conventions is lost. Commit the directory.
Numbering Convention for Larger Projects
For projects with many rule files, a numeric prefix convention makes load order and precedence explicit:
.cursor/rules/
├── 001-base.mdc # Always apply, fundamental conventions
├── 010-typescript.mdc # Language-specific rules
├── 020-react.mdc # Frontend framework rules
├── 030-api.mdc # Backend rules
├── 040-database.mdc # Data layer rules
├── 050-testing.mdc # Test conventions
├── 100-security.mdc # Agent-requested security checklist
└── 200-deployment.mdc # Manual deployment procedures
Cursor loads rules in filename order, with later files overriding earlier ones on conflicts. Numbering makes the override hierarchy visible without reading each file.
What About AGENTS.md?
Cursor added support for AGENTS.md — a plain markdown alternative to .mdc files. It lives at the project root (or in subdirectories for path-scoped rules) and does not require frontmatter.
Think of AGENTS.md as a middle ground: more flexible than .cursorrules (supports nested directories for path scoping) but less powerful than MDC (no frontmatter, no glob patterns, no activation modes).
For most use cases, go directly to MDC. AGENTS.md is primarily useful if you want rules that work across multiple AI tools simultaneously — Claude Code also respects AGENTS.md in multi-agent scenarios.
Building a Rule Library
If you are building up a library of reusable rules — either for your own projects or to share with your team — the MDC format scales much better than .cursorrules. A well-organized .cursor/rules/ directory can serve as a transferable template.
We maintain a gallery of community-submitted rules, including Cursor-specific examples, at our rules gallery. The collection includes language-specific conventions, framework templates, and security checklists in both .cursorrules and .mdc formats.
For more context on how .cursorrules compares to CLAUDE.md and other rule formats across AI coding tools, see our cross-tool comparison guide. If you are migrating away from Cursor entirely, our migration guide covers how to translate your rules to CLAUDE.md format.
For practical templates to get started quickly, our Cursor rules examples and templates guide has copy-pasteable starting points for common stacks.
The short version: if you have not touched Agent mode and your project is small, .cursorrules is fine. The moment you enable Agent mode, you need MDC — your existing rules are invisible to it. Migration takes under an hour for most projects and the payoff is immediate.