Cursor evolved from a single-file rules system to a sophisticated multi-file architecture:
Evolution Timeline:
2023: .cursorrules (single Markdown file)
2024: .cursor/rules/*.mdc (multi-file with metadata)
2025: Enhanced .mdc with rule types, globs, priority
Current Recommended Approach (2025):
my-project/
├── .cursor/
│ └── rules/
│ ├── index.mdc # Project overview
│ ├── typescript.mdc # Language rules
│ ├── react.mdc # Framework rules
│ ├── testing.mdc # QA guidelines
│ └── security.mdc # Security standards
└── .cursorrules # DEPRECATED (but still works)
Key Architectural Differences
| Aspect |
.cursorrules (Legacy) |
.mdc (Modern) |
|---|---|---|
| Format | Plain Markdown | Markdown + YAML frontmatter |
| Location | Project root |
.cursor/rules/ directory |
| Metadata | None | YAML: globs, alwaysApply, description
|
| Activation | Always loaded | Conditional (based on context) |
| Modularity | Single monolithic file | Multiple focused files |
| Rule Types | Manual only | Always, Auto-Attached, Agent-Requested, Manual |
| Token Efficiency | Entire file loaded | Only relevant rules loaded |
| Scoping | Global to project | File-pattern specific |
When to Use Each Format
Use .cursorrules (Legacy) If:
- ✅ Quick setup for personal projects
- ✅ Migrating from other tools (Windsurf, Claude Code)
- ✅ Small project (<10 rules)
- ✅ Single developer, no complex requirements
Use .mdc (Modern) If:
- ✅ Professional/team projects (recommended)
- ✅ Multiple programming languages in one repo
- ✅ Need conditional rule activation
- ✅ Large ruleset (>15 rules)
- ✅ Token optimization important
- ✅ Want Cursor's latest features
Migration Path
Step 1: Assess Current .cursorrules
# Check if you have legacy file
ls -la .cursorrules
# Count lines (if >200, definitely migrate to .mdc)
wc -l .cursorrules
Step 2: Create Modern Structure
# Create directory
mkdir -p .cursor/rules
# Split by topic
# (Manual process - see Section 10 for strategies)
Step 3: Verify Both Work
# Keep .cursorrules as backup during transition
mv .cursorrules .cursorrules.backup
# Test with .mdc files
# If issues, restore: mv .cursorrules.backup .cursorrules
2. File Locations and Discovery Order
Cursor's File Discovery Algorithm
When Cursor starts, it scans for rules in this exact order:
Priority 1 (Highest):
./.cursor/rules/*.mdc
Priority 2 (Fallback):
./.cursorrules
Priority 3 (User Global):
~/Documents/Cursor/Rules/*.mdc
(macOS/Linux)
%USERPROFILE%\Documents\Cursor\Rules\*.mdc
(Windows)
Priority 4 (Lowest):
Default Cursor prompts
File System Layout
Project-Level Rules:
my-project/
├── .cursor/
│ ├── rules/
│ │ ├── index.mdc # Always-apply project context
│ │ ├── typescript.mdc # *.ts, *.tsx files
│ │ ├── python.mdc # *.py files
│ │ ├── api.mdc # api/ directory
│ │ └── testing.mdc # *.test.* files
│ └── settings.json # NOT for rules (UI preferences)
└── .cursorrules # Legacy fallback
Global User Rules:
macOS/Linux:
~/Documents/Cursor/Rules/
├── my-coding-style.mdc # Personal preferences
├── company-standards.mdc # Organization rules
└── language-defaults.mdc # Default patterns
Windows:
C:\Users\YourName\Documents\Cursor\Rules\
├── my-coding-style.mdc
└── ...
Naming Conventions
File naming impacts load order (alphabetical):
.cursor/rules/
├── 00-index.mdc # Loads first (project context)
├── 10-typescript.mdc # Core language
├── 20-react.mdc # Framework
├── 30-testing.mdc # Quality
├── 40-security.mdc # Security
└── 99-overrides.mdc # Loads last (exceptions)
Recommended Naming Pattern:
[NN]-[category]-[specific].mdc
Examples:
00-index.mdc # Always-apply baseline
10-lang-typescript.mdc # Language rules
20-framework-nextjs.mdc # Framework rules
30-lib-trpc.mdc # Library-specific
40-domain-auth.mdc # Feature-specific
50-qa-testing.mdc # Quality assurance
Hidden Files and .cursor Directory
Important Notes:
# .cursor/ is automatically git-ignored by Cursor
# BUT you should version control rules:
# .gitignore
.cursor/settings.json # Don't commit (user preferences)
.cursor/rules/ # DO commit (team standards)
# Explicitly track rules
git add -f .cursor/rules/
3. Rule Types and Activation Mechanisms
The Four Rule Types
Cursor infers rule type from frontmatter combinations (no explicit type field):
# TYPE 1: Always
alwaysApply: true
# (globs and description ignored)
# TYPE 2: Auto-Attached
alwaysApply: false
globs: ["src/**/*.ts"]
# (auto-loads when editing matching files)
# TYPE 3: Agent-Requested
alwaysApply: false
description: "Apply when working with authentication"
# (AI decides based on description)
# TYPE 4: Manual
alwaysApply: false
# (no globs, no description - only via @mention)
Type 1: Always Rules
Behavior: Loaded for every Cursor request (chat, CMD-K, Composer).
Use For:
- Project overview and context
- Universal coding standards
- Critical security requirements
- Tech stack information
Example:
---
description: "Core project standards for all code"
alwaysApply: true
---
# Project Context
**Stack**: Next.js 15, TypeScript, PostgreSQL
**Architecture**: Monorepo with Turborepo
**Deployment**: Vercel
## Universal Rules
1. TypeScript strict mode required
2. All async functions return `Promise<Result<T>>`
3. Never commit secrets or API keys
4. Run `pnpm lint` before committing
5. 80% test coverage minimum
Token Cost: High (always included), so keep concise (target: <100 lines).
Type 2: Auto-Attached Rules
Behavior: Loaded automatically when editing files matching glob patterns.
Use For:
- Language-specific rules (TypeScript vs Python)
- Framework conventions (React vs Vue)
- Directory-specific patterns (API vs UI)
- File-type standards (tests, configs, docs)
Example:
---
description: "TypeScript coding standards"
globs:
- "src/**/*.ts"
- "src/**/*.tsx"
- "!**/*.test.ts" # Exclude test files
alwaysApply: false
---
# TypeScript Standards
## Type Annotations
All functions MUST have explicit return types:
typescript
// ✅ CORRECT
export function calculateTotal(items: Item[]): number {
return items.reduce((sum, item) => sum + item.price, 0);
}
// ❌ WRONG - implicit return type
export function calculateTotal(items: Item[]) {
return items.reduce((sum, item) => sum + item.price, 0);
}
Token Cost: Medium (loaded only when relevant files open).
Type 3: Agent-Requested Rules
Behavior: AI decides whether to include based on natural language description.
Use For:
- Context-specific guidance (security audits, performance optimization)
- Specialized workflows (migration procedures, refactoring patterns)
- Advanced topics (not always needed)
Example:
---
description: "Apply when handling authentication, user sessions, or security-sensitive operations"
alwaysApply: false
---
# Security Standards for Authentication
## When to Use This Rule
This rule applies to:
- User authentication flows
- Session management
- Password handling
- JWT token operations
- OAuth integrations
## Critical Requirements
### 1. Password Security
typescript
// ✅ CORRECT - bcrypt with salt rounds ≥12
import bcrypt from 'bcrypt';
async function hashPassword(password: string): Promise {
const saltRounds = 12;
return await bcrypt.hash(password, saltRounds);
}
// ❌ NEVER store plaintext passwords
const user = { password: plainPassword }; // FORBIDDEN
### 2. JWT Storage
typescript
// ✅ CORRECT - HttpOnly cookies
res.cookie('token', jwt, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'lax',
maxAge: 15 * 60 * 1000 // 15 minutes
});
// ❌ NEVER - localStorage or sessionStorage
localStorage.setItem('token', jwt); // XSS vulnerability
Token Cost: Low (only when AI deems relevant).
How AI Decides:
- Analyzes your chat message or selected code
- Checks if keywords match description
- Loads rule if contextually appropriate
Type 4: Manual Rules
Behavior: Only loaded when explicitly mentioned with @rulename or added to context.
Use For:
- Reference documentation
- Specialized procedures (deployment checklists)
- Optional guidelines
- Advanced patterns (rarely used)
Example:
---
description: "Deployment checklist and procedures"
alwaysApply: false
---
# Production Deployment Checklist
Invoke with: `@deployment-checklist`
## Pre-Deployment
- [ ] All tests passing (`pnpm test`)
- [ ] TypeScript check clean (`pnpm type-check`)
- [ ] Linter passes (`pnpm lint --max-warnings 0`)
- [ ] Build succeeds locally (`pnpm build`)
- [ ] Environment variables updated in Vercel dashboard
- [ ] Database migrations dry-run on staging
- [ ] Rollback plan documented
## Deployment Steps
1. Merge to `main` branch
2. Wait for Vercel auto-deploy
3. Verify preview URL
4. Run smoke tests
5. Monitor error tracking (Sentry)
## Post-Deployment
- [ ] Health check endpoints responding
- [ ] Critical user flows tested
- [ ] Performance metrics reviewed
- [ ] No error spikes in logs
Token Cost: Zero (unless explicitly invoked).
Rule Type Decision Matrix
| Your Need | Rule Type | Frontmatter |
|---|---|---|
| Project overview, universal standards | Always | alwaysApply: true |
| Language-specific (TS vs Python) | Auto-Attached | globs: ["**/*.ts"] |
| Framework patterns (React) | Auto-Attached | globs: ["**/*.tsx"] |
| Directory-specific (API layer) | Auto-Attached | globs: ["src/api/**"] |
| Context-dependent (security) | Agent-Requested | description: "security operations" |
| Specialized (deployment) | Manual | No globs, no description |
4. The Complete .mdc File Specification
Anatomy of an .mdc File
---
[YAML FRONTMATTER - Metadata]
---
[MARKDOWN BODY - Instructions]
Minimal Valid .mdc File
---
description: "Basic project rules"
alwaysApply: true
---
# Project Rules
Use TypeScript strict mode for all code.
Complete .mdc File with All Features
---
# METADATA SECTION (YAML)
# Required: Human-readable description
description: "TypeScript and React coding standards for frontend"
# Optional: Glob patterns for auto-attachment
globs:
- "src/**/*.{ts,tsx}"
- "app/**/*.{ts,tsx}"
- "!**/*.test.{ts,tsx}" # Exclude tests
- "!**/*.stories.{ts,tsx}" # Exclude Storybook
# Optional: Always apply regardless of context
alwaysApply: false
# Optional: Tags for categorization (not widely used yet)
tags:
- frontend
- typescript
- react
# Optional: Priority (higher numbers = higher priority)
priority: 10
---
# MARKDOWN BODY SECTION
## Section 1: Context
This rule applies to TypeScript and React code in the frontend.
## Section 2: Standards
### Type Safety
typescript
// ✅ CORRECT
function Component({ user }: { user: User }): JSX.Element {
return
}
// ❌ WRONG
function Component({ user }) {
return
}
## Section 3: References
See also: [api-patterns.ts](mdc:src/lib/api-patterns.ts)
YAML Frontmatter Field Reference
| Field | Type | Required | Default | Purpose |
|---|---|---|---|---|
description |
string | Yes | - | Human-readable summary (shown in UI) |
globs |
array[string] | No | [] |
File patterns for auto-attachment |
alwaysApply |
boolean | No | false |
Load for all requests |
tags |
array[string] | No | [] |
Categorization (future feature) |
priority |
integer | No | 0 |
Conflict resolution (higher wins) |
Invalid/Unsupported Fields:
# ❌ These don't work (common mistakes):
ruleType: "always" # No explicit type field
model: "claude-3.5" # Model selection is separate
enabled: true # No enable/disable flag
version: "1.0" # No versioning support
author: "John Doe" # No author metadata
Markdown Body Features
Supported Markdown Syntax:
# Headers (H1-H6)
## Subheaders
**Bold**, *Italic*, `Inline Code`
- Unordered lists
- Nested lists
- Sub-item
1. Ordered lists
2. Numbered items
| Tables | Are | Supported |
|--------|-----|-----------|
| Value | Yes | Works |
typescript
// Code blocks with syntax highlighting
function example() {
return "works";
}
> Blockquotes are supported
---
Horizontal rules work
Special Cursor Features:
# File References (mdc: links)
See pattern: [utils.ts](mdc:src/lib/utils.ts)
# This tells Cursor to include that file's content in context
File Size Recommendations
| File Type | Target Size | Max Size | Why |
|---|---|---|---|
| index.mdc (Always) | 50-100 lines | 150 lines | Token efficiency |
| Language rules | 100-200 lines | 300 lines | Keep focused |
| Framework rules | 150-250 lines | 350 lines | Examples needed |
| Reference docs | 200-500 lines | 800 lines | Manual invoke anyway |
Total Project Rules: Target <1500 lines combined (all .mdc files).
Part II: Configuration Deep Dive
5. YAML Frontmatter Reference
description Field
Purpose: Shown in Cursor's UI when rules are listed; used by AI for Agent-Requested rule selection.
Best Practices:
# ✅ GOOD: Specific and actionable
description: "Apply when editing React components in src/components/"
# ✅ GOOD: Describes when to use (Agent-Requested)
description: "Security standards for authentication and user data handling"
# ❌ BAD: Too vague
description: "Frontend rules"
# ❌ BAD: Too long (truncated in UI)
description: "This rule contains comprehensive guidelines for writing TypeScript code including type annotations, error handling patterns, testing strategies, and performance optimization techniques for React applications in our Next.js monorepo"
Character Limit: Aim for <120 characters (fits in UI without truncation).
globs Field
Purpose: File patterns for auto-attachment (gitignore-style syntax).
Syntax Reference:
globs:
# Single pattern
- "*.ts" # All .ts files in root
# Recursive
- "**/*.ts" # All .ts files anywhere
- "src/**/*.ts" # All .ts files in src/
# Multiple extensions
- "**/*.{ts,tsx}" # TypeScript files
- "**/*.{js,jsx,ts,tsx}" # All JavaScript/TypeScript
# Specific directories
- "src/api/**/*" # Everything in src/api/
- "components/**/*.tsx" # React components
# Exclusions (! prefix)
- "!**/*.test.ts" # Exclude tests
- "!**/*.spec.ts" # Exclude specs
- "!**/node_modules/**" # Exclude dependencies
# Complex patterns
- "src/{api,lib}/**/*.ts" # Multiple dirs
- "**/*.{test,spec}.{ts,tsx}" # Test files
Pattern Matching Rules:
| Pattern | Matches | Doesn't Match |
|---|---|---|
*.ts |
app.ts, utils.ts
|
src/app.ts, app.tsx
|
**/*.ts |
src/app.ts, lib/utils.ts
|
app.tsx |
src/** |
src/app.ts, src/lib/util.ts
|
lib/app.ts |
!**/*.test.ts |
(excludes) | app.test.ts |
Common Patterns Library:
# TypeScript only
globs: ["**/*.ts", "!**/*.test.ts"]
# TypeScript + React
globs: ["**/*.{ts,tsx}", "!**/*.test.{ts,tsx}"]
# Frontend only
globs: ["src/components/**/*", "src/app/**/*"]
# Backend only
globs: ["src/api/**/*", "src/lib/db/**/*"]
# Tests only
globs: ["**/*.{test,spec}.{ts,tsx,js,jsx}"]
# Config files only
globs: ["*.config.{js,ts}", ".*rc.{js,json}"]
# Everything except tests and node_modules
globs:
- "src/**/*"
- "!**/*.test.*"
- "!**/node_modules/**"
Testing Your Globs:
# Use glob tools to test patterns
npm install -g glob
# Test pattern
glob "src/**/*.{ts,tsx}" --ignore "**/*.test.*"
alwaysApply Field
Purpose: Force rule to load for every Cursor request.
Values:
alwaysApply: true # Always load
alwaysApply: false # Load conditionally (default)
When to Use true:
✅ DO use for:
- Project overview (1 file max)
- Critical security requirements
- Universal coding standards (applicable to all files)
- Tech stack information
❌ DON'T use for:
- Language-specific rules (use globs instead)
- Framework patterns (use globs)
- Optional guidelines (use Agent-Requested or Manual)
- Large rule sets (token waste)
Token Impact Example:
# Scenario: 5 rules files, 200 lines each = 1000 lines total
# If all have alwaysApply: true
# Every request loads: 1000 lines × ~4 tokens/line = 4000 tokens
# Cost: Wasted on Python edits when you have React rules
# If using globs appropriately
# TypeScript edit loads: 400 lines × 4 tokens = 1600 tokens
# Savings: 60% fewer tokens, faster responses
tags Field (Experimental)
Purpose: Categorization for future Cursor features (limited use in 2025).
Syntax:
tags:
- frontend
- typescript
- react
- testing
Current Status: Metadata only; doesn't affect rule behavior. May enable filtering in future Cursor versions.
priority Field (Advanced)
Purpose: Resolve conflicts when multiple rules apply to same context.
Behavior:
# typescript.mdc
---
priority: 5
---
Max function length: 50 lines
# typescript-exceptions.mdc
---
priority: 10 # Higher priority wins
---
Complex algorithms: up to 100 lines allowed
Default: All rules have priority 0 if unspecified.
Use Cases:
- Project-specific overrides of global rules
- Exception handling (higher priority = exception)
- Conflicting team standards (resolve with priority)
Best Practice: Avoid if possible; fix conflicting rules instead.
YAML Syntax Gotchas
Common Mistakes:
# ❌ WRONG: Tabs instead of spaces
description:→"Uses tab character"
# ✅ CORRECT: 2 or 4 spaces
description: "Uses spaces"
# ❌ WRONG: Missing quotes around special chars
description: Apply when: editing auth code
# ✅ CORRECT: Quote strings with colons
description: "Apply when: editing auth code"
# ❌ WRONG: Single quotes inside single quotes
description: 'It's broken'
# ✅ CORRECT: Use double quotes or escape
description: "It's working"
description: 'It''s working'
# ❌ WRONG: Invalid YAML structure
globs:
- "*.ts"
- "*.tsx" # Misaligned
# ✅ CORRECT: Consistent indentation
globs:
- "*.ts"
- "*.tsx"
Validation:
# Use YAML linter
npm install -g yaml-lint
yaml-lint .cursor/rules/*.mdc
# Or online: https://www.yamllint.com/
6. Markdown Body Structure
Recommended Hierarchy
# Top-Level Topic (H1)
## Category (H2)
### Specific Rule (H3)
#### Implementation Detail (H4)
- Bullet points for lists
- Keep bullets focused (1 idea each)
Depth Recommendations:
| Level | Purpose | Example |
|---|---|---|
H1 #
|
File title/topic | # TypeScript Standards |
H2 ##
|
Major category | ## Type Safety |
H3 ###
|
Specific rule | ### Explicit Return Types |
H4 ####
|
Implementation | #### Function Declarations |
| H5+ | Avoid | Too deep for AI parsing |
Code Block Best Practices
Always Include Language Identifiers:
✅ GOOD - Language specified:
typescript
function example() {
return "syntax highlighting works";
}
❌ BAD - No language:
function example() {
return "no highlighting";
}
Good vs Bad Pattern:
## Error Handling
### ❌ WRONG: Silent Failures
typescript
try {
await operation();
} catch {
// Silent error
}
**Problems:**
- No logging
- User not informed
- Debugging impossible
### ✅ CORRECT: Explicit Handling
typescript
try {
await operation();
} catch (error) {
logger.error('Operation failed', { error });
return { success: false, error: 'User-friendly message' };
}
**Benefits:**
- Error logged for debugging
- User receives feedback
- Maintains type safety
Table Formatting
Decision Tables:
| Use Case | Solution | Example |
|----------|----------|---------|
| Server data | TanStack Query | `useQuery('users', fetchUsers)` |
| Form state | React Hook Form | `useForm()` |
| Local state | useState | `const [open, setOpen] = useState(false)` |
Comparison Tables:
| Pattern | Pros | Cons | When to Use |
|---------|------|------|-------------|
| Server Component | SEO, fast initial load | No interactivity | Static content |
| Client Component | Interactive, hooks | Slower initial load | Dynamic UI |
Emphasis and Formatting
**REQUIRED**: Bold for mandatory items
*Recommended*: Italic for suggestions
`code`: Inline code for functions, files, commands
ALWAYS: All caps for critical directives
NEVER: All caps for prohibitions
Link References
External Documentation:
See Next.js docs for Server Components: https://nextjs.org/docs/app/building-your-application/rendering/server-components
Note: Cursor won't fetch URLs automatically; AI relies on training data.
Internal File References (mdc: scheme):
Follow the pattern in [api-client.ts](mdc:src/lib/api-client.ts)
See error handling: [errors.ts](mdc:src/utils/errors.ts)
(Detailed in Section 8)
Structuring Large Rule Files
Template for 200+ Line Files:
---
description: "Complete React component standards"
globs: ["**/*.{tsx,jsx}"]
---
# React Component Standards
## Table of Contents
1. [Component Structure](#structure)
2. [Props and Types](#props)
3. [State Management](#state)
4. [Performance](#performance)
5. [Testing](#testing)
---
<a name="structure"></a>
## 1. Component Structure
[Content]
---
<a name="props"></a>
## 2. Props and Types
[Content]
---
[etc.]
Section Separators:
Use horizontal rules (---) between major sections for visual clarity.
7. Glob Pattern Mastery
Glob Syntax Quick Reference
| Pattern | Meaning | Example Matches |
|---|---|---|
* |
Any characters (single level) |
*.ts → app.ts, utils.ts
|
** |
Any characters (recursive) |
**/*.ts → src/app.ts, lib/db/users.ts
|
? |
Single character |
?.ts → a.ts, 1.ts (not app.ts) |
[abc] |
Character set |
[abc].ts → a.ts, b.ts, c.ts
|
{a,b} |
Alternatives |
*.{ts,tsx} → app.ts, App.tsx
|
! |
Negation (exclude) |
!*.test.ts → Excludes test files |
Real-World Pattern Examples
Pattern 1: TypeScript Files Only
globs:
- "**/*.ts" # All .ts files
- "**/*.tsx" # All .tsx files
- "!**/*.test.ts" # Exclude tests
- "!**/*.spec.ts" # Exclude specs
- "!**/*.d.ts" # Exclude type declarations
- "!**/node_modules/**" # Exclude dependencies
# Shorthand version:
globs:
- "**/*.{ts,tsx}"
- "!**/*.{test,spec,d}.{ts,tsx}"
- "!**/node_modules/**"
Pattern 2: Frontend Components Only
globs:
- "src/components/**/*.{tsx,jsx}"
- "src/app/**/*.{tsx,jsx}" # Next.js App Router
- "!**/*.stories.{tsx,jsx}" # Exclude Storybook
- "!**/*.test.{tsx,jsx}" # Exclude tests
Pattern 3: Backend API Layer
globs:
- "src/api/**/*" # All files in API directory
- "src/lib/db/**/*" # Database layer
- "src/services/**/*" # Business logic
- "!**/*.test.*" # Exclude tests
Pattern 4: Test Files Only
globs:
- "**/*.test.{ts,tsx,js,jsx}"
- "**/*.spec.{ts,tsx,js,jsx}"
- "**/__tests__/**/*"
- "tests/**/*"
Pattern 5: Configuration Files
globs:
- "*.config.{js,ts,mjs,cjs}" # webpack.config.js, etc.
- ".*rc.{js,json,yaml,yml}" # .eslintrc.js, etc.
- ".*.{js,json,yaml,yml}" # .prettierrc, etc.
- "package.json"
- "tsconfig.json"
Advanced Glob Techniques
Technique 1: Multi-Directory Matching
# Match files in EITHER api/ OR lib/ directories
globs:
- "src/{api,lib}/**/*.ts"
# Expands to:
# - src/api/**/*.ts
# - src/lib/**/*.ts
Technique 2: Specific File Names
# Match specific filenames anywhere
globs:
- "**/{schema,types,models}.ts"
# Matches:
# - src/schema.ts
# - lib/types.ts
# - db/models.ts
Technique 3: Depth Limiting
# Only immediate children (not recursive)
globs:
- "src/*.ts" # src/app.ts (yes)
# src/lib/utils.ts (no)
# One level deep only
globs:
- "src/*/*.ts" # src/lib/utils.ts (yes)
# src/lib/api/users.ts (no)
Technique 4: Complex Exclusions
# Include TypeScript, exclude tests AND storybook
globs:
- "**/*.{ts,tsx}"
- "!**/*.{test,spec}.{ts,tsx}"
- "!**/*.stories.{ts,tsx}"
- "!**/__tests__/**"
- "!**/__mocks__/**"
Testing Glob Patterns
Method 1: Use Node.js glob Library
npm install -g glob-cli
# Test pattern
glob "**/*.{ts,tsx}" --ignore "**/*.test.*"
Method 2: Manual Verification
# Create test structure
mkdir -p test-globs/src/{api,components}
touch test-globs/src/api/{users,posts}.ts
touch test-globs/src/components/{Button,Card}.tsx
touch test-globs/src/components/Button.test.tsx
# Test with find command
find test-globs -name "*.tsx" ! -name "*.test.*"
Method 3: Cursor's Built-in Test
1. Create .mdc file with globs
2. Open matching file in Cursor
3. Open Cursor chat
4. Check if rule appears in active rules indicator
5. Adjust globs if not loading
Common Glob Mistakes
# ❌ MISTAKE 1: Forgetting to escape
globs:
- src/**/*.{ts,tsx} # Missing quotes
# ✅ FIX:
globs:
- "src/**/*.{ts,tsx}"
# ❌ MISTAKE 2: Wrong directory separator (Windows)
globs:
- "src\\api\\**\\*.ts" # Backslashes don't work
# ✅ FIX: Always use forward slashes
globs:
- "src/api/**/*.ts"
# ❌ MISTAKE 3: Overly broad patterns
globs:
- "**/*" # Matches EVERYTHING (slow!)
# ✅ FIX: Be specific
globs:
- "src/**/*.{ts,tsx}"
# ❌ MISTAKE 4: Exclusion after inclusion doesn't work
globs:
- "**/*.ts"
- "!**/*.test.ts" # Exclusion ignored!
# ✅ FIX: Combine into one glob or use precise inclusion
globs:
- "**/*.ts"
- "!**/*.test.ts"
- "!**/node_modules/**"
8. File References with mdc: Links
What Are mdc: Links?
Purpose: Tell Cursor to include another file's content as context when this rule is loaded.
Syntax:
See the pattern in [filename](mdc:path/to/filename)
How It Works:
When Cursor loads the rule file, it:
1. Parses all [text](mdc:path) links
2. Reads the referenced files
3. Includes their content in the AI context
4. AI can now reference those patterns
Use Cases
Use Case 1: Reference Canonical Implementations
---
description: "API route patterns"
globs: ["src/api/**/*.ts"]
---
# API Route Standards
Follow the pattern established in [users-router.ts](mdc:src/api/routers/users-router.ts)
## Key Points
All routes must:
- Use tRPC procedures
- Include Zod input validation
- Return Result<T> type
- Log errors with context
The reference file shows all these patterns in action.
Use Case 2: Link to Type Definitions
---
description: "Error handling standards"
---
# Error Handling
Use the Result<T> type defined in [types.ts](mdc:src/lib/types.ts)
All async operations must return Promise<Result<T>>.
Use Case 3: Reference Configuration
---
description: "Testing standards"
globs: ["**/*.test.ts"]
---
# Testing Standards
Test configuration is in [vitest.config.ts](mdc:vitest.config.ts)
Use the same setup patterns for all test files.
Path Resolution
Paths are relative to project root:
# ✅ CORRECT - From project root
[utils.ts](mdc:src/lib/utils.ts)
# ❌ WRONG - Relative to rules file
[utils.ts](mdc:../../src/lib/utils.ts)
# ✅ CORRECT - Root-level files
[config](mdc:next.config.js)
Multiple File References
---
description: "Complete authentication patterns"
---
# Authentication Standards
See these reference files:
- **Types**: [auth-types.ts](mdc:src/types/auth.ts)
- **Implementation**: [auth-service.ts](mdc:src/services/auth-service.ts)
- **Routes**: [auth-router.ts](mdc:src/api/routers/auth-router.ts)
- **Tests**: [auth.test.ts](mdc:src/services/auth-service.test.ts)
These files demonstrate our complete auth pattern from end to end.
Best Practices
DO:
- ✅ Reference small, focused files (<200 lines)
- ✅ Link to canonical implementations
- ✅ Reference type definitions
- ✅ Link to config files that show patterns
DON'T:
- ❌ Reference very large files (>500 lines) - token waste
- ❌ Link to dependencies in node_modules
- ❌ Chain too many references (>5 files per rule)
- ❌ Reference files that might not exist (breaks gracefully but wastes tokens)
Token Impact
# Example rule: 100 lines
# + 3 referenced files: 50 lines each
# Total context: 100 + (3 × 50) = 250 lines
# If rule loads for every TypeScript edit:
# 250 lines × 4 tokens/line = 1000 tokens per request
# Recommendation: Use mdc: links sparingly
Alternatives to mdc: Links
Alternative 1: Inline Examples (Preferred for Small Patterns)
# Instead of: See [auth.ts](mdc:src/auth.ts)
# DO: Inline the pattern directly
typescript
// Standard auth pattern:
export async function authenticateUser(
credentials: Credentials
): Promise> {
// ... implementation
}
Alternative 2: Written Descriptions
# Instead of: See [config.ts](mdc:config.ts)
# DO: Describe the pattern
Config file uses this structure:
1. Import from environment
2. Validate with Zod schema
3. Export frozen object
Part III: Practical Implementation
9. Quick Start: Your First Rule File
Scenario: New Next.js + TypeScript Project
Step 1: Create Directory Structure
# From your project root
mkdir -p .cursor/rules
cd .cursor/rules
Step 2: Create Your First Rule (index.mdc)
touch index.mdc
Step 3: Add Basic Configuration
---
description: "Core project standards for all code"
alwaysApply: true
---
# Project Overview
**Type**: Full-stack web application
**Stack**: Next.js 15, TypeScript 5.4, PostgreSQL
**Architecture**: Monorepo with Turborepo
## Critical Rules
1. **TypeScript Strict Mode**: All code must compile with strict mode
2. **Server Components First**: Use Server Components by default, add 'use client' only when needed
3. **Error Handling**: All async functions return `Promise<Result<T>>`
4. **Testing**: 80% coverage minimum
5. **No Secrets**: Never commit API keys or secrets
## Tech Stack
- **Frontend**: Next.js 15 (App Router), React 19, Tailwind CSS
- **Backend**: tRPC 11, Drizzle ORM
- **Database**: PostgreSQL 16
- **Testing**: Vitest, Playwright
- **Package Manager**: pnpm (NOT npm)
## Common Commands
bash
pnpm dev # Start dev server
pnpm test # Run tests
pnpm lint # Run linter
pnpm build # Production build
Step 4: Test Your Configuration
# 1. Open Cursor
# 2. Open a TypeScript file
# 3. Open Cursor chat (CMD/CTRL + L)
# 4. Ask: "What are the top 3 project rules?"
# 5. Verify it mentions your rules
Expected Response:
Based on the project rules:
1. TypeScript Strict Mode - All code must compile with strict mode enabled
2. Server Components First - Use Server Components by default in Next.js,
only add 'use client' when interactivity is needed
3. Error Handling - All async functions should return Promise<Result<T>>
Would you like help implementing any of these patterns?
Step 5: Add Language-Specific Rules
touch typescript.mdc
---
description: "TypeScript coding standards"
globs:
- "**/*.ts"
- "**/*.tsx"
- "!**/*.test.ts"
alwaysApply: false
---
# TypeScript Standards
## Type Annotations
All functions MUST have explicit return types:
typescript
// ✅ CORRECT
export function calculateTotal(items: Item[]): number {
return items.reduce((sum, item) => sum + item.price, 0);
}
// ❌ WRONG - No return type
export function calculateTotal(items: Item[]) {
return items.reduce((sum, item) => sum + item.price, 0);
}
## No `any` Type
typescript
// ❌ NEVER use any
function process(data: any) {
return data.value;
}
// ✅ Use unknown + type guards
function process(data: unknown) {
if (typeof data === 'object' && data !== null && 'value' in data) {
return (data as { value: unknown }).value;
}
throw new Error('Invalid data');
}
Step 6: Verify File Loading
# Directory structure should now be:
.cursor/rules/
├── index.mdc # Always loaded
└── typescript.mdc # Loaded for .ts/.tsx files
# Test:
# 1. Open a TypeScript file
# 2. Cursor should load both rules
# 3. Try generating a function
# 4. Verify it includes return type
10. Single-File vs Multi-File Strategy
Decision Matrix
| Project Size | Developers | Languages | Recommended Approach |
|---|---|---|---|
| Small (<5k LOC) | 1-2 | 1 | Single .cursorrules
|
| Medium (5-20k LOC) | 2-5 | 1-2 | 3-5 .mdc files |
| Large (20-100k LOC) | 5-15 | 2-3 | 8-12 .mdc files |
| Enterprise (100k+ LOC) | 15+ | 3+ | 15-20 .mdc files |
Single-File Approach
When to Use:
- Personal projects
- Proof of concepts
- Quick prototypes
- Learning/experimentation
Structure:
my-project/
├── .cursorrules # Single file with all rules
└── src/
Example .cursorrules:
# Project Rules
## Stack
Next.js 15, TypeScript, PostgreSQL
## Standards
- TypeScript strict mode
- Functional components
- Result<T> for errors
- 80% test coverage
## Patterns
### Error Handling
typescript
type Result =
| { success: true; data: T }
| { success: false; error: string };
### Components
Use Server Components by default.
Pros:
- ✅ Simple setup
- ✅ Easy to edit (one file)
- ✅ No configuration needed
Cons:
- ❌ All rules always loaded (token waste)
- ❌ Hard to organize beyond ~200 lines
- ❌ No conditional loading
Multi-File Approach
When to Use:
- Professional projects
- Team collaboration
- Multiple languages/frameworks
- Large codebases
Structure:
my-project/
├── .cursor/rules/
│ ├── 00-index.mdc # Project overview (Always)
│ ├── 10-typescript.mdc # Language rules (Glob)
│ ├── 20-react.mdc # Framework rules (Glob)
│ ├── 30-testing.mdc # Testing rules (Manual)
│ └── 40-security.mdc # Security rules (Agent-Requested)
└── src/
Pros:
- ✅ Highly scalable
- ✅ Optimized token usage (conditional loading)
- ✅ Clear ownership (frontend team owns react.mdc)
- ✅ Easier to maintain
Cons:
- ❌ Requires setup
- ❌ Requires understanding YAML frontmatter
Migration: Single → Multi-File
Step 1: Identify Categories
Read your .cursorrules and group content:
- Overview/Stack
- Language-Specific
- Framework-Specific
- Testing
- Deployment
Step 2: Create Files
mkdir -p .cursor/rules
# Create files
touch .cursor/rules/{index,typescript,react,testing}.mdc
Step 3: Move Content
- Move Overview →
index.mdc(setalwaysApply: true) - Move TS rules →
typescript.mdc(setglobs: ["**/*.ts"]) - Move React rules →
react.mdc(setglobs: ["**/*.tsx"]) - Move Testing →
testing.mdc(setglobs: ["**/*.test.ts"])
Step 4: Delete Legacy File
rm .cursorrules
11. Project Templates by Stack
Template 1: React + TypeScript SaaS
File: .cursor/rules/react-saas.mdc
---
description: "React SaaS development standards"
globs:
- "src/**/*.{ts,tsx}"
- "app/**/*.{ts,tsx}"
---
# React SaaS Standards
## Tech Stack
- **Framework**: Next.js 15
- **Auth**: NextAuth.js v5
- **Database**: PostgreSQL + Drizzle
- **Payments**: Stripe
## Component Patterns
### Layout Components
tsx
// ✅ Use layout components for structure
export function DashboardLayout({ children }: { children: ReactNode }) {
return (
{children}
);
}
### Data Fetching (Server Components)
tsx
// ✅ Fetch directly in Server Components
export default async function DashboardPage() {
const user = await currentUser();
const stats = await db.query.stats.findMany({
where: eq(stats.userId, user.id)
});
return ;
}
## Multi-Tenancy
**CRITICAL**: All database queries MUST filter by `organizationId`.
typescript
// ✅ CORRECT
const projects = await db.query.projects.findMany({
where: and(
eq(projects.orgId, user.orgId), // Tenant filter
eq(projects.status, 'active')
)
});
// ❌ WRONG (Security Risk!)
const projects = await db.query.projects.findMany({
where: eq(projects.status, 'active') // Missing tenant filter!
});
Template 2: Python FastAPI Microservice
File: .cursor/rules/fastapi.mdc
---
description: "FastAPI microservice standards"
globs: ["**/*.py"]
---
# FastAPI Standards
## Stack
- Python 3.12
- FastAPI 0.110
- SQLAlchemy 2.0 (Async)
- Pydantic 2.6
## Route Definitions
python
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from app.db import get_db
from app.schemas import UserCreate, UserResponse
router = APIRouter()
@router.post("/users/", response_model=UserResponse, status_code=201)
async def create_user(
user: UserCreate,
db: AsyncSession = Depends(get_db)
):
"""Create a new user with email validation."""
db_user = await get_user_by_email(db, email=user.email)
if db_user:
raise HTTPException(status_code=400, detail="Email already registered")
return await create_user(db=db, user=user)
## Pydantic Models
python
from pydantic import BaseModel, EmailStr, Field
class UserBase(BaseModel):
email: EmailStr
is_active: bool = True
class UserCreate(UserBase):
password: str = Field(..., min_length=8)
class UserResponse(UserBase):
id: int
class Config:
from_attributes = True # Replaces orm_mode=True
## Async Database
ALWAYS use async/await with database sessions.
python
✅ CORRECT
result = await session.execute(select(User))
users = result.scalars().all()
❌ WRONG (Blocking)
users = session.query(User).all()
Template 3: Node.js + Express API
File: .cursor/rules/express-api.mdc
---
description: "Express API standards"
globs: ["src/**/*.ts", "!**/*.test.ts"]
---
# Express API Standards
## Stack
- Node.js 20
- Express 5.0
- TypeScript 5.4
- Prisma ORM
## Route Handler Pattern
ALL handlers must be async and use `next(error)` for errors (or express-async-errors).
typescript
import { Request, Response, NextFunction } from 'express';
import { z } from 'zod';
// Input validation schema
const CreateUserSchema = z.object({
email: z.string().email(),
password: z.string().min(8)
});
export const createUser = async (
req: Request,
res: Response,
next: NextFunction
) => {
try {
// 1. Validate input
const { email, password } = CreateUserSchema.parse(req.body);
// 2. Business logic
const user = await userService.create({ email, password });
// 3. Send response
res.status(201).json({
success: true,
data: user
});
} catch (error) {
// 4. Handle error
next(error);
}
};
## Error Handling Middleware
typescript
// src/middleware/error.ts
export const errorHandler = (
err: Error,
req: Request,
res: Response,
next: NextFunction
) => {
logger.error(err);
if (err instanceof ZodError) {
return res.status(400).json({
success: false,
error: 'Validation Error',
details: err.errors
});
}
res.status(500).json({
success: false,
error: 'Internal Server Error'
});
};
12. Rules Organization Patterns
Pattern 1: The Layered Onion
Organize rules by scope, from general to specific.
.cursor/rules/
├── 00-global.mdc # Applies everywhere (Stack, Overview)
├── 10-language/
│ ├── ts.mdc # TypeScript rules
│ └── sql.mdc # SQL rules
├── 20-framework/
│ ├── react.mdc # React rules
│ └── tailwind.mdc # CSS rules
└── 30-domain/
├── auth.mdc # Auth logic
└── billing.mdc # Billing logic
Pattern 2: The Monorepo Split
For repositories containing multiple projects.
.cursor/rules/
├── index.mdc # Root context
├── apps-web.mdc # globs: ["apps/web/**/*"]
├── apps-mobile.mdc # globs: ["apps/mobile/**/*"]
├── packages-ui.mdc # globs: ["packages/ui/**/*"]
└── packages-db.mdc # globs: ["packages/db/**/*"]
Pattern 3: The Lifecycle Workflow
Organize by development lifecycle phase.
.cursor/rules/
├── 01-planning.mdc # Manual: Architecture guidelines
├── 02-coding.mdc # Auto: Coding standards
├── 03-testing.mdc # Auto: Test files
├── 04-review.mdc # Agent-Requested: Code review checklist
└── 05-deploy.mdc # Manual: Deployment steps
Part IV: Advanced Techniques
13. Rule Priority and Conflict Resolution
When multiple rules apply to the same file, Cursor merges them. Use priority to control conflicts.
Scenario:
-
global.mdcsays: "Max line length 80 chars" -
python.mdcsays: "Max line length 100 chars"
Resolution:
# python.mdc
---
globs: ["**/*.py"]
priority: 10 # Higher wins (default is 0)
---
Max line length: 100 chars
Merging Behavior:
- Cursor concatenates rule content
- Higher priority rules appear later in the context window (closer to the prompt)
- LLMs pay more attention to instructions at the end (recency bias)
Best Practice:
- Keep priorities simple (0, 10, 20)
- Use priority only for exceptions
- Default (0): Standard rules
- High (10): Specific overrides
- Critical (20): Security mandates
14. Context Window Optimization
The Token Budget Problem
AI models have limited context windows (e.g., 200k tokens).
- Code: 80% of budget
- Chat History: 15% of budget
- Rules: 5% of budget (~10k tokens max recommended)
Optimization Strategies:
1. Strict Globs
Don't load React rules for backend files.
# ❌ Bad
globs: ["**/*.ts"]
# ✅ Good
globs: ["apps/web/**/*.tsx", "apps/web/**/*.ts"]
2. Manual Loading for Heavy Docs
Don't auto-load 500-line testing guides.
# testing-guide.mdc
---
description: "Testing guide"
alwaysApply: false # Don't auto-load
# No globs
---
Invoke with @testing-guide when needed.
3. Reference over Inclusion
Instead of pasting 200 lines of type definitions, link to the file.
See types in [types.ts](mdc:src/types.ts)
4. Concise Examples
Use minimal code examples that demonstrate the pattern, not full files.
15. Team Collaboration Workflows
Git Workflow
1. Commit Rules
Always commit .cursor/rules/ to git.
git add .cursor/rules
git commit -m "chore: update AI coding standards"
2. Pull Request Reviews
Review rule changes just like code.
- Are they clear?
- Do they work?
- Are examples correct?
3. Shared vs Local
-
Shared:
.cursor/rules/(Committed) -
Local:
.cursorrules(Git-ignored, optional)
Sample .gitignore:
.cursor/settings.json # User preferences
.cursor/rules/ # KEEP this (don't ignore)
.cursorrules # IGNORE if using for local overrides
Onboarding New Devs
Day 1 Task:
- Clone repo
- Open in Cursor
- Open chat and ask: "What are the coding standards for this project?"
- Verify AI responds with content from
.cursor/rules/index.mdc
16. Migration and Maintenance
Migration from Other Tools
From Windsurf:
- Convert
.windsurfrulescontent to.cursor/rules/index.mdc - Move file-specific sections to separate
.mdcfiles withglobs
From GitHub Copilot:
- Copy
.github/copilot-instructions.mdto.cursor/rules/index.mdc - Add
alwaysApply: true
From Claude Code:
- Copy
CLAUDE.mdto.cursor/rules/index.mdc - Add
alwaysApply: true
Maintenance Schedule
Monthly:
- Review
index.mdcfor tech stack updates - Check if new patterns emerged
- Remove unused rules
Quarterly:
- Full audit of all
.mdcfiles - Test rules against new Cursor features
- Verify effectiveness metrics
Part V: Troubleshooting and Best Practices
17. Common Issues and Solutions
Issue 1: Rules Not Loading
Symptoms: AI ignores standards, doesn't mention rules when asked.
Troubleshooting:
-
Check location: Must be in
.cursor/rules/(not.cursor/) -
Check extension: Must be
.mdc(not.md) -
Check frontmatter: Verify
alwaysApply: trueor matchingglobs - Check formatting: Valid YAML (no tabs)
- Reload: Restart Cursor (Cmd+R)
Issue 2: Conflict Between Rules
Symptoms: AI follows one rule but ignores another contradictory one.
Solution:
- Check priorities (higher wins)
- Check file specificity (more specific globs should have higher priority)
- Merge conflicting files into one logic flow
Issue 3: "Too Many Rules" Warning
Symptoms: Cursor warns about context usage.
Solution:
- Review
alwaysApplyusage (reduce count) - Tighten
globsto load fewer files - Move documentation-heavy rules to Manual activation
18. Performance Tuning
Latency vs Quality Trade-off:
- More Rules = Higher Quality, Higher Latency, Higher Cost
- Fewer Rules = Lower Quality, Faster Response, Lower Cost
Sweet Spot:
- 1 Always-Apply file (Overview)
- 2-3 Auto-Attached files active per request
- < 2000 tokens total rules context
19. Testing Rule Effectiveness
The "Gold Standard" Test:
- Delete a complex function in your codebase
- Ask AI to regenerate it: "Implement the user calculation function"
- Compare result with original
- Iterate rules until AI produces near-identical code
The "Violation" Test:
-
Create a file violating standards (e.g.,
anytype) - Ask AI: "Review this file for issues"
- Verify AI catches the violation based on your rules
20. Production Examples Library
Example A: Python Data Science
.cursor/rules/python-ds.mdc
---
description: "Python data science standards"
globs: ["**/*.py", "**/*.ipynb"]
---
# Data Science Standards
## Libraries
- Use `pandas` for tabular data
- Use `polars` for large datasets (>1GB)
- Use `plotly` for interactive charts
- Use `matplotlib` for static reports
## Code Style
- Use type hints: `def process(df: pd.DataFrame) -> pd.Series:`
- Docstrings: Google style
- No global state in scripts
## Notebooks
- Keep imports in first cell
- Restart & Run All must work
- No hardcoded paths (use `pathlib`)
Example B: Rust Systems Programming
.cursor/rules/rust.mdc
---
description: "Rust coding standards"
globs: ["**/*.rs"]
---
# Rust Standards
## Error Handling
- Use `anyhow` for applications
- Use `thiserror` for libraries
- No `unwrap()` in production code (use `expect` or `?`)
## Async
- Use `tokio` runtime
- Prefer `async/await` over `poll`
- Use `tracing` for logs
## Testing
- Unit tests in same file module `mod tests`
- Integration tests in `tests/` directory
- Run `cargo clippy` before commit
Example C: Go Microservices
.cursor/rules/go.mdc
---
description: "Go microservice standards"
globs: ["**/*.go"]
---
# Go Standards
## Error Handling
- Check all errors
- Wrap errors with context: `fmt.Errorf("failed to fetch user: %w", err)`
- Don't panic
## Concurrency
- Use `context` for cancellation/timeout
- Use `errgroup` for managing goroutines
- Close channels appropriately
## Project Layout
- Standard Go Project Layout
- `cmd/` for main applications
- `internal/` for private application code
- `pkg/` for library code
This guide represents the complete state of Cursor configuration as of 2025. By following these patterns, you transform Cursor from a smart editor into a specialized member of your engineering team.
Top comments (0)