OpenBooklet
Sign In
Tips & Tricks6 min read

Cursor Rules That Actually Work: Production-Tested .cursorrules for Every Tech Stack

Liam Park|Published March 28, 2026|Updated March 28, 2026

The old .cursorrules file at your project root is deprecated. Cursor still reads it, but the deprecation warning is there for a reason. The new system --- .mdc files in .cursor/rules/ --- is better in every way that matters: scoped activation, glob patterns, lower token cost, and rules that only load when they're relevant.

Most developers are either still using the legacy format or haven't configured rules at all. Both waste the most powerful leverage point Cursor offers: teaching it how your specific project works.

Here are production-tested rules for every major tech stack, the new .mdc format explained, and the eight mistakes that make Cursor ignore your instructions.

Key Takeaways

  • .cursorrules is deprecated. Move to .cursor/rules/*.mdc files with frontmatter-based activation.
  • The new format has four activation types: Always, Auto-Attached (globs), Agent-Requested (description), and Manual (@mention)
  • Scoped rules save tokens --- only relevant rules load into context, not everything at once
  • cursor.directory and awesome-cursorrules (38.7K stars) are the community's best rule sources
  • The #1 mistake: rules too long. Critical instructions get lost in the middle. Keep each rule file focused.

Short Answer

What should I do? Create a .cursor/rules/ directory. Add focused .mdc files with proper frontmatter --- one for general conventions (alwaysApply: true), others scoped by glob pattern (*.tsx, /api/, *.test.ts). Keep each file under 200 lines. Migrate your old .cursorrules content into this structure. Delete the legacy file.


The New Format: .mdc Files

The .mdc (Markdown with Components) format adds a YAML frontmatter header to markdown rules. This header controls when and how the rule activates.

Directory Structure

project-root/
├── .cursor/
│   └── rules/
│       ├── general.mdc          # alwaysApply: true
│       ├── react-components.mdc # globs: **/*.tsx, **/*.jsx
│       ├── api-routes.mdc       # globs: **/api/**/*.ts
│       ├── testing.mdc          # globs: **/*.test.ts, **/*.spec.ts
│       └── database.mdc         # globs: **/db/**, **/models/**
└── src/

Frontmatter Fields

---
description: Short description of what this rule covers
globs: **/*.tsx, **/*.jsx
alwaysApply: false
---

# Your rules in markdown here

Four Activation Types

Type alwaysApply globs description When It Loads
Always true empty optional Every conversation
Auto-Attached false pattern set optional When matching files are in context
Agent-Requested false empty required AI reads description, decides if relevant
Manual false empty optional Only when you type @rulename

Use "Always" sparingly --- only for conventions that apply to every file in the project. Use "Auto-Attached" with globs for everything else. This keeps your context lean.


Production Rules by Tech Stack

React / Next.js / Tailwind

File: .cursor/rules/react-nextjs.mdc

---
description: React and Next.js conventions for this project
globs: **/*.tsx, **/*.jsx, **/app/**/*.ts
alwaysApply: false
---

You are an expert in TypeScript, Next.js 15 App Router, React 19, and Tailwind CSS 4.

Key Principles:
- Use functional components with TypeScript interfaces
- Use Server Components by default, 'use client' only when needed
- Prefer named exports for components
- Use lowercase-with-dashes for directories (components/auth-wizard/)
- Descriptive variable names with auxiliary verbs (isLoading, hasError)

Component Patterns:
- Props as TypeScript interfaces, not type aliases
- Prefer composition over prop drilling
- Use Suspense boundaries for async components
- Error boundaries on route segments

Styling:
- Tailwind CSS utility classes only, no CSS modules
- Use cn() utility for conditional classes
- Mobile-first responsive design
- Design tokens via CSS custom properties

Next.js Specifics:
- generateMetadata for all public pages
- next/image for all images
- Route handlers in app/api/ with proper error responses
- Parallel routes and intercepting routes where appropriate

NEVER:
- Use class components
- Use default exports for components
- Use inline styles
- Use CSS-in-JS libraries
- Import from 'react' (auto-imported in React 19)

Python / FastAPI

File: .cursor/rules/python-fastapi.mdc

---
description: Python and FastAPI conventions
globs: **/*.py
alwaysApply: false
---

You are an expert in Python 3.12+, FastAPI, and scalable API development.

Key Principles:
- Type hints on ALL function signatures
- Pydantic v2 BaseModel for all request/response schemas
- async def for database and external API operations
- def for pure computation functions
- File naming: lowercase with underscores (routers/user_routes.py)

FastAPI Patterns:
- Dependency injection for state management and auth
- Router-level dependencies for shared middleware
- Background tasks for non-blocking operations
- Proper status codes (201 for created, 204 for deleted)

Error Handling:
- Custom exception handlers, not bare try/except
- HTTPException with detail messages for API errors
- Structured error responses: {"detail": "message", "code": "ERROR_CODE"}

Performance:
- Async database drivers (asyncpg, motor)
- Connection pooling via dependencies
- Redis caching for expensive operations
- Lazy loading for large datasets

NEVER:
- Use raw dicts where Pydantic models work
- Use synchronous database calls in async routes
- Catch broad exceptions without logging
- Store secrets in code or config files

Go

File: .cursor/rules/golang.mdc

---
description: Go conventions and patterns
globs: **/*.go
alwaysApply: false
---

You are an expert in Go 1.22+, using the standard library where possible.

Project Layout:
- cmd/ for entry points
- internal/ for private packages
- pkg/ for public libraries
- api/ for OpenAPI specs

Key Principles:
- Short, focused functions with single responsibility
- Always handle errors explicitly; wrap with fmt.Errorf("context: %w", err)
- Accept interfaces, return structs
- Table-driven tests with t.Parallel()
- GoDoc comments on all public functions

Patterns:
- Context propagation for cancellation and timeouts
- Middleware for cross-cutting concerns (logging, auth, tracing)
- Functional options pattern for configurable constructors
- Graceful shutdown with signal handling

Naming:
- CamelCase for exports, camelCase for private
- Receiver names: single letter matching type (func (s *Server))
- Interface names: -er suffix when possible (Reader, Writer)

NEVER:
- Use init() functions (explicit initialization instead)
- Ignore error returns
- Use global state or package-level variables for mutable state
- Use panic for recoverable errors

TypeScript Strict

File: .cursor/rules/typescript-strict.mdc

---
description: TypeScript strict mode conventions
globs: **/*.ts, **/*.tsx
alwaysApply: false
---

TypeScript Rules (strict: true):
- noImplicitAny, strictNullChecks, exactOptionalPropertyTypes enabled
- Use interface over type for object shapes (better errors, extendable)
- Prefer const assertions and satisfies operator
- Use discriminated unions over optional fields for variants
- No any --- use unknown + type guards instead
- Exhaustive switch with never checks
- Use branded types for IDs: type UserId = string & { __brand: 'UserId' }

Patterns:
- Zod schemas for runtime validation at boundaries
- Infer types from schemas: type User = z.infer<typeof userSchema>
- Generic constraints over type assertions
- Narrowing with in, instanceof, and custom type guards

NEVER:
- Use any (use unknown)
- Use @ts-ignore (use @ts-expect-error with explanation)
- Use non-null assertion (!) without documented justification
- Use enums (use const objects with as const)

The General Rules File

Every project needs one "always on" rule file for project-wide conventions:

File: .cursor/rules/general.mdc

---
description: Project-wide conventions and commands
alwaysApply: true
---

# Project: [Your Project Name]

Tech Stack: [framework] [version], [language], [database], [hosting]

Commands:
- Test single file: [your test command]
- Type check: [your typecheck command]
- Build: [your build command]
- Lint: [your lint command]

Git:
- Branch naming: feature/, fix/, chore/
- Conventional commits (feat:, fix:, chore:)

CRITICAL:
- ALWAYS run typecheck after modifying TypeScript files
- NEVER commit .env files or credentials
- NEVER use console.log in production code

Keep this under 50 lines. Everything else goes in scoped rule files.


Testing Rules

File: .cursor/rules/testing.mdc

---
description: Testing conventions and patterns
globs: **/*.test.ts, **/*.test.tsx, **/*.spec.ts, **/__tests__/**
alwaysApply: false
---

Testing Framework: [Jest/Vitest/Playwright]

Principles:
- Test behavior, not implementation
- One assertion concept per test (multiple expects are fine if testing one behavior)
- Descriptive test names: "should [expected behavior] when [condition]"
- Arrange-Act-Assert structure

Patterns:
- Factory functions for test data, not raw object literals
- Mock at boundaries (API calls, database), not internal functions
- Integration tests for API routes, unit tests for pure logic
- Snapshot tests only for serializable output, never for components

NEVER:
- Test private methods directly
- Use random data without seeds
- Leave .only() or .skip() in committed tests
- Mock modules you own (refactor instead)

Migrating from .cursorrules

If you have an existing .cursorrules file:

  1. Create .cursor/rules/ directory
  2. Split your monolithic file into focused .mdc files by concern
  3. Add frontmatter to each file with appropriate activation
  4. Move framework-specific rules to glob-matched files
  5. Keep only truly universal rules in alwaysApply: true
  6. Delete the old .cursorrules file

The migration is worth the effort. A single 300-line .cursorrules file loads into every conversation, consuming ~2,000 tokens. Five scoped .mdc files load only when relevant, typically consuming 400-800 tokens per conversation. That's 60-80% fewer tokens spent on instructions.


The Eight Mistakes

1. Rules Too Long

The #1 failure. Research shows AI models remember instructions at the beginning and end but forget the middle. A 200-line rule file means your critical conventions in the middle get ignored. Keep each .mdc file under 100 lines.

2. Vague Instructions

"Write clean code" and "prefer good patterns" get completely ignored. Be concrete: "Use Pydantic v2 BaseModel for all request/response schemas" works. "Write good schemas" doesn't.

3. Not Splitting Rules

One massive file wastes tokens. Split by concern (components, API, testing, database) with proper globs. Only relevant rules load, saving context for actual code.

4. Conflicting with the Codebase

If your codebase uses pattern A but rules say pattern B, Cursor follows the codebase. Either update rules to match reality or refactor the code to match the rules. Contradictions waste tokens and produce inconsistent output.

5. Outdated Rules

Specifying Next.js 13 patterns when your project uses Next.js 15 causes confident generation of deprecated code. Keep rules in sync with your dependencies.

6. Malformed Frontmatter

Missing alwaysApply field, broken YAML syntax, or glob patterns that match nothing. Rules silently fail. Test by checking if Cursor follows them on a matching file.

7. Rules Forgotten Mid-Conversation

After many messages, Cursor's context optimization may push rules out. Starting fresh conversations for new features helps. For critical rules, saying "remember the project rules" can re-anchor them.

8. Over-Specifying Globally

20 global alwaysApply: true rules add approximately 2,000 tokens to every single message. That's context budget taken from actual code. Be ruthless about what truly needs to be always-on.

Debugging tip: If Cursor behaves strangely, temporarily move .cursor/rules/ to a backup location. If behavior improves, you have rule overload. Add rules back one at a time to find the conflict.


Where to Find More Rules

  • cursor.directory --- Community-maintained library, browseable by framework
  • awesome-cursorrules --- 38,700+ GitHub stars, the largest collection
  • cursorrules.org --- AI-powered rule generator
  • Cursor's /Generate Cursor Rules command --- Analyzes your codebase and generates starter rules

Cursor Rules vs CLAUDE.md vs AGENTS.md

Feature Cursor .mdc CLAUDE.md AGENTS.md
Format YAML frontmatter + Markdown Plain Markdown Plain Markdown
Activation 4 types (Always, Auto, Agent, Manual) Always loaded Always loaded
Glob patterns Yes (frontmatter) No native globs No
File imports @file references @path imports No
Scoping Per-file-type, per-directory Project + directory level Project level
Multi-tool Cursor only Claude Code only Multi-tool compatible

If your team uses multiple AI tools, maintain both Cursor rules and CLAUDE.md (or AGENTS.md). Tools like rule-porter can convert between formats. For a deep dive on Claude Code configuration, see our post on the CLAUDE.md playbook.


FAQ

Should I commit .cursor/rules/ to git?

Yes. Project rules are team conventions that should be shared. Personal preferences go in Cursor Settings > General > Rules for AI (not version controlled).

Do .cursorrules still work?

Yes, but they show a deprecation warning. Cursor still reads them, but the recommendation is to migrate to .cursor/rules/*.mdc. No hard removal date has been announced.

How many rule files should I have?

3-7 for most projects. One general (always-on), plus scoped files for your main concerns: components, API, testing, database, styling. More than 10 suggests you're over-engineering rules.

Can I use @file references inside rules?

Yes. @path/to/file inside a rule body references another file. Useful for pointing to examples or schemas without embedding them in the rule.

Do rules work in Cursor's Agent mode?

Yes. Agent mode reads all applicable rules before starting work. Auto-Attached rules activate based on the files the agent touches.


Key Takeaways

  1. Migrate to .mdc format --- scoped activation and glob patterns save 60-80% of token overhead versus a monolithic .cursorrules
  2. Split rules by concern --- one file per domain (components, API, testing), not one file for everything
  3. Be specific, not aspirational --- "Use Pydantic v2 BaseModel" beats "write clean code"
  4. Keep each file under 100 lines --- critical instructions in the middle of long files get ignored
  5. The ecosystem has your back --- cursor.directory, awesome-cursorrules (38.7K stars), and the /Generate Cursor Rules command give you a head start

Further reading: The CLAUDE.md Playbook: 12 Rules That Work | Context Window Mastery

Ready to supercharge your AI agents?

OpenBooklet is the free, open skills marketplace for AI agents. Discover verified skills, publish your own, and make your agents smarter.

Browse Skills

About the author

Liam helps developers get the most out of AI coding tools. He writes practical guides, tips, and deep dives on agent-native development.

Liam Park · Developer Advocate

Related Articles