Custom Cursor Rules: Templates That Actually Work in 2026
There are hundreds of Cursor rules templates floating around GitHub and Reddit. Most of them share the same problem: they were written as aspirational documentation, not tested constraints. They bloat the always-apply context slot with 300-line manifestos about code quality, and the agent ignores half of it while hallucinating the other half. The templates in this article are shorter, scoped, and built around what MDC files actually do well.
If you want the full explanation of how .cursor/rules/ works—activation modes, the plan-then-implement loop, committing the rules directory to git—read Building Your First Cursor Custom Workflow in 2026 first. This article skips the primer and goes straight to templates.
How MDC Files Work (the Short Version)
Rules in .cursor/rules/ are markdown files with YAML frontmatter. The frontmatter controls when Cursor loads the rule:
| Frontmatter | Activation | When to use |
|---|---|---|
alwaysApply: true | Every chat, every file | Project-wide norms only |
globs: ["src/**/*.tsx"] | When a matching file is in context | Language/directory-specific rules |
description: "..." (no globs, no alwaysApply) | Agent decides based on description | Workflow rules the agent should pull in when relevant |
| Neither field | Manual @rule-name only | One-off or rarely-needed rules |
Cursor’s official documentation recommends keeping rules under 500 lines and splitting large guidance into composable files. In practice, the sweet spot for a scoped rule is 20–50 lines — short enough that the agent reads it fully rather than skimming it into compression.
One key data point from the official Cursor rules docs: the documentation introduced an AGENTS.md file as a simpler alternative for straightforward projects that don’t need per-directory scoping. For complex projects, the full .cursor/rules/ directory with individual MDC files is still the right approach.
Why Generic Rules Fail
The most common failure pattern: someone copies a 200-line “ultimate Cursor rules” gist from GitHub into their alwaysApply rule. The rule says things like “always write clean, maintainable code” and “follow SOLID principles.” These instructions do nothing because:
- They compete with the base model’s existing knowledge. Claude Sonnet and GPT-4o already know what SOLID means. Telling them again fills token space without adding project-specific constraints.
- Vague instructions produce vague compliance. “Use TypeScript best practices” gives the agent room to do whatever it was going to do anyway.
- Always-apply rules load for every request. A 200-line always-apply rule means 200 lines of context consumed every time you ask the agent to rename a variable.
Rules work when they encode things the base model cannot know: your specific codebase’s conventions. Named exports vs default exports. Where test files live. Which state library you use. Whether useEffect for data fetching is banned. These are things the agent cannot infer from general training.
The rule of thumb from Cursor’s agent best practices: add a rule when you’ve corrected the agent for the same mistake three times. Before that, you’re pre-optimizing.
Template 1: TypeScript / React Project Rules
Two files. One always-apply for stack-wide constraints, one scoped to your component directory.
.cursor/rules/project-globals.mdc (always-apply, keep under 30 lines):
---
description: Project-wide TypeScript and stack conventions
alwaysApply: true
---
# Project globals
- TypeScript strict mode is enabled. Never use `any`; use `unknown` with type guards instead.
- Package manager is pnpm. Do not suggest npm or yarn commands.
- State: Zustand for client state. TanStack Query for server state. No `useEffect` for data fetching.
- Validation: Zod for all runtime validation. Define schemas in `src/schemas/`.
- Shared types live in `src/types/`. Import from there, do not inline type definitions in component files.
- All public API routes have a corresponding integration test in `__tests__/integration/`.
- Do not add a new npm package without noting it explicitly and asking for confirmation.
.cursor/rules/react-components.mdc (scoped, auto-attached):
---
description: React component conventions for src/components
globs: ["src/components/**/*.tsx", "src/components/**/*.ts", "src/app/**/*.tsx"]
alwaysApply: false
---
# React component rules
- Named exports only. No default exports, ever.
- Co-locate styles: `Button.tsx` + `Button.module.css`. No global CSS mutations.
- Components stay under 200 lines. If larger, extract subcomponents into the same folder.
- Use `useId()` for any element that needs a stable ID (forms, labels, ARIA).
- Server components are the default. Add `'use client'` only when you need browser APIs or event handlers.
- Props interface naming: `ButtonProps`, `CardProps` (ComponentNameProps pattern).
- Test files sit next to the component: `Button.tsx` → `Button.test.tsx`.
- shadcn/ui is the component library. Use its primitives before building custom ones.
- No inline styles. Tailwind classes only.
These two files cover the most common source of Cursor drift in React projects: default exports, mixed state libraries, and components that grow to 400 lines because the agent didn’t know where to stop.
For deeper configuration of TypeScript and React-specific Cursor settings beyond rules, see Best Cursor Settings for TypeScript and React in 2026.
Template 2: Python Backend Rules
Python projects have different drift patterns. The agent tends to import libraries you haven’t installed, use bare dict where you’d prefer dataclass or Pydantic, and skip type annotations on function signatures.
.cursor/rules/python-backend.mdc (scoped):
---
description: Python backend conventions for this service
globs: ["src/**/*.py", "app/**/*.py", "tests/**/*.py"]
alwaysApply: false
---
# Python backend rules
## Type annotations
- All function signatures must have type annotations (parameters and return type).
- Use `dataclass` or Pydantic `BaseModel` for structured data. Never use bare `dict` for data
that has a known shape.
- `Optional[X]` is acceptable; prefer `X | None` syntax (Python 3.10+ union style).
## Imports
- No wildcard imports (`from module import *`).
- Standard library imports first, then third-party, then local — separated by blank lines (PEP8).
- Do not import a library that is not in `requirements.txt` or `pyproject.toml`. Ask before adding.
## Error handling
- Catch specific exceptions, not bare `except Exception`.
- Log errors with `logger.exception()` to preserve the traceback. Do not use `print()` for errors.
## Testing
- Tests live in `tests/` and mirror the `src/` directory structure.
- Fixtures go in `conftest.py`. Do not define fixtures inside test files.
- Prefer `pytest.mark.parametrize` over copy-pasted test functions.
## Style
- PEP8 throughout. `ruff` is configured for this project — do not bypass it.
- No magic numbers. Name constants in `src/constants.py`.
- Docstrings use Google style for all public functions and classes.
The two most-loaded rules here are the import rule and the dict-vs-dataclass rule. Cursor in Python mode defaults to dict heavily in generated code, and it will happily suggest import pandas in a project that has never installed it. These rules catch both.
For the full Cursor settings layer that complements these rules, see Best Cursor Settings for Python Developers in 2026.
Template 3: Code Review Rules
This rule is manual-only — you invoke it with @code-review when you want the agent to evaluate a diff rather than generate code. The goal is to give the agent a consistent checklist rather than letting it freelance on what to check.
.cursor/rules/code-review.mdc (manual):
---
description: Code review checklist — invoke with @code-review when reviewing a diff or PR
---
# Code review mode
When reviewing code, work through this checklist in order. Report findings by severity (Critical / High / Medium / Low).
## Security
- No secrets, API keys, or tokens hardcoded or logged.
- SQL queries use parameterized statements, not string concatenation.
- User input is validated before being used in file paths, shell commands, or DB queries.
- Auth checks happen at the top of functions that require authentication, not mid-function.
## Correctness
- Off-by-one errors in loops and slice operations.
- Null/undefined/None checks where applicable.
- Async code: are await calls present where needed? Are errors handled in async branches?
- Side effects: does this function modify shared state unexpectedly?
## Naming and readability
- Variable and function names reflect purpose, not implementation.
- Boolean variables start with `is`, `has`, or `should`.
- No abbreviations except for universally understood ones (`id`, `url`, `ctx`).
## Test coverage
- Are edge cases covered (empty input, boundary values, error paths)?
- Are new functions testable (no hidden dependencies, no global state mutations)?
## What NOT to flag
- Style issues that linters already catch (formatting, import order).
- Subjective naming choices that don't reduce clarity.
- Performance micro-optimizations without a measured baseline.
The last section (“What NOT to flag”) is as important as the checklist. Without it, the agent will pad its review with linting-level noise that buries real issues.
Template 4: Agent Mode Guardrails
This is the template most developers wish they had written before their first bad Agent Mode session. By default, Cursor Agent will delete files, add packages, and modify unrelated files if its plan calls for it. These guardrails don’t prevent the agent from working — they require explicit confirmation before it crosses the lines that create the most recovery work.
.cursor/rules/agent-guardrails.mdc (always-apply):
---
description: Guardrails for Cursor Agent mode — prevent common destructive actions
alwaysApply: true
---
# Agent mode guardrails
These rules apply whenever you are operating in Agent mode (making file changes, running commands).
## Before taking any of these actions, stop and ask for confirmation:
- Deleting any file (including test files, config files, or "unused" utilities).
- Adding a new package to package.json, requirements.txt, pyproject.toml, or any lock file.
- Modifying files outside the directory or module the current task is scoped to.
- Renaming a file that is imported elsewhere in the codebase.
- Running a migration, seed command, or any command that modifies a database.
- Changing environment variable names or adding new ones to .env files.
## Hard stops (do not proceed, ask first):
- Do not delete or overwrite `.env`, `.env.local`, or any secret/credential file.
- Do not run `git reset`, `git clean`, or `git push --force`.
- Do not modify `package-lock.json`, `pnpm-lock.yaml`, or `poetry.lock` directly.
## Scope discipline:
- Only edit files that are directly part of the requested change.
- If you notice an unrelated bug while implementing a task, note it in a comment
(`// TODO: [issue description]`) but do not fix it in this session.
- Do not refactor code that is not part of the task, even if the refactor is obvious.
The scope discipline section at the bottom is where most unsolicited changes come from. Cursor Agent is trained to be helpful, and “helpful” to a language model often means fixing adjacent problems it notices. For a developer who wants predictable, reviewable diffs, this is more annoying than helpful.
Where to Store Rules: Project vs Global
Project rules go in .cursor/rules/ in your repository root and are committed to git. This is the right place for 95% of rules because rules encode codebase conventions, and conventions should travel with the codebase. When a new developer clones the repo, they get the same agent behavior without any setup.
Global rules go in ~/.cursor/rules/ (or configured via Cursor’s global settings). Use global rules only for personal preferences that apply to every project you work on and aren’t appropriate to share with teammates: your preferred comment style, a reminder to always suggest tests, a note about your debugging workflow.
The common mistake is putting project-specific rules in global settings. When those rules refer to files or patterns in a specific project (e.g., src/components/**/*.tsx), they silently apply to every other project and either do nothing or cause confusion.
Common Mistakes
Rules that are too long. Cursor’s recommendation is 500 lines max; the practical ceiling for a rule the agent actually reads and applies is closer to 50. If your rule is 200 lines, it needs to be three rules with narrower scopes.
Rules that contradict each other. If your React rule says “use Tailwind classes only” and your always-apply rule says “prefer CSS modules,” the agent will make an arbitrary choice and both rules will feel ignored. Audit your rule set as a set, not as individual files.
Rules that fight the base model. “Always add comments to every function” will produce comment spam because the agent interprets it as requiring a comment on every line. “Add JSDoc comments to all exported functions” is specific enough to get useful output. Instructions that are too broad give the model room to over-apply them.
Not testing glob patterns. If you write globs: ["src/*.tsx"] when you meant src/**/*.tsx, the rule will never fire for files in subdirectories. Test your patterns against actual file paths before committing.
Using rules as a substitute for linting. Rules are model-level guidance; linters are enforced constraints. If you care about import order being correct in CI, configure ruff or ESLint — don’t write a rule and hope the agent complies every time. Rules are for conventions that linters can’t check (naming patterns, architectural decisions, “ask before adding packages”).
Honest Take: What Rules Actually Fix
Rules are good at style enforcement — the kind of preferences that experienced teams have but that aren’t worth writing a lint plugin for. Named exports, test file co-location, which state library to use for which concern. These are high-value rules that save the 30 seconds of correcting the agent’s first draft every single time.
Rules are not good at logic correctness. Telling the agent “always validate user input” in a rule does not make it write correct validation logic. It might add a Zod schema call that doesn’t actually cover the attack surface. For correctness, you still need code review — which is why Template 3 above is manual-only rather than always-on.
The practical upshot: a well-configured rules set reduces correction cycles on style and structure by a noticeable margin. It does not turn Agent mode into a reliable autonomous developer. The Cursor IDE Review 2026 goes into this distinction in more detail — the tool is most valuable as an accelerator with a developer in the loop, not as a replacement for that developer.
If the discipline needed to use rules well feels like the harder part, a vibe coding survival guide for solo developers covers the mindset shifts that make AI-assisted development sustainable.
Set up Templates 1 and 4 first. They cover the two highest-ROI problems: keeping generated code consistent with your conventions, and keeping Agent mode from making changes you didn’t ask for. Add Templates 2 and 3 when you have a Python backend or find yourself doing code review in Cursor. Resist the urge to write a new rule every time the agent does something wrong — if it’s a one-off, fix it manually. If it happens three times, write the rule.
Sources
- Cursor Rules — Cursor official documentation (cursor.com/docs/rules)
- Best Practices for Coding with Agents — Cursor blog
- awesome-cursorrules — 150+ community-contributed .cursorrules templates (GitHub, PatrickJS)
- Cursor Rules: Complete .mdc Guide & 15 Templates — Vibe Coding Academy
- A Year with Cursor: Workflow Evolution from Agent to Architect — Subramanya N (January 2026)
- Cursor IDE Complete Guide 2026 — Codersera
Last updated May 13, 2026. Cursor’s rules format and activation modes have changed before — verify current frontmatter syntax against cursor.com/docs/rules before relying on specifics.
Was this article helpful?
Thanks for the feedback — it helps improve future articles.