02 - Cursor Rules: Configure AI for Your Project Standards
Every developer has their own conventions, architectural patterns, and quality standards. When working with a human colleague, these rules are communicated through code reviews, pair programming, and documentation. But how do you communicate the same expectations to an AI agent? Cursor's answer is the Rules system: a powerful and flexible mechanism that lets you instruct the AI on how to generate, modify, and reason about your project's code.
In this article, we will explore every aspect of Cursor's Rules system: from its historical evolution to advanced configuration strategies, complete with practical examples for Angular, React, Python, backend APIs, and much more. By the end, you will have all the tools to transform Cursor's AI into a collaborator that respects your team's conventions as if it had always known them.
What You Will Learn
- The evolution of the Rules system: from
.cursorrulesto the.cursor/rules/directory - The four rule types: Always, Auto Attached, Agent Requested, and Manual
- The difference between User Rules and Project Rules and when to use each
- How to write effective rules with frontmatter, globs, and descriptions
- Complete examples for Angular, React, Python, FastAPI, and REST APIs
- Advanced strategies: conditional rules, rule inheritance, automatic generation
- Team workflows: sharing via git, onboarding, and shared conventions
- Comparison with CLAUDE.md and other AI instruction systems
Cursor IDE and AI-Native Development Series Overview
| # | Article | Focus |
|---|---|---|
| 1 | Complete Cursor IDE Guide | Full overview |
| 2 | You are here - Cursor Rules | Custom AI configuration |
| 3 | Agent Mode | Advanced automation |
| 4 | Plan Mode | AI-assisted planning |
| 5 | Hooks and MCP | Extensibility and integrations |
| 6 | Professional Workflows | Production best practices |
The Evolution of Cursor's Rules System
Cursor's Rules system has undergone significant evolution since its initial introduction. Understanding this history is essential to grasp why the current system is structured the way it is and to avoid confusion between the different generations of configuration.
First Generation: The .cursorrules File
In the first implementation, Cursor supported a single .cursorrules file in the project root.
This file contained free-form text instructions that were injected into the context of every AI interaction.
It was simple and straightforward: write your rules in a file, and the AI follows them.
You are a senior developer specializing in Angular and TypeScript.
Code rules:
- Always use standalone components
- Prefer signals over BehaviorSubject
- Use OnPush change detection in all components
- Always write unit tests for services
- Follow Angular naming conventions (kebab-case for files)
Response style:
- Respond in English
- Explain the reasoning behind each choice
- Include error handling in every example
This approach had an obvious limitation: all rules ended up in a single monolithic file.
In a complex project with an Angular frontend, Python backend, Docker infrastructure, and CI/CD pipelines,
the .cursorrules file quickly became enormous and hard to maintain. Furthermore, all rules
were always sent to the AI, even when they were irrelevant to the current context.
Second Generation: Project Rules with .cursor/rules/
To address these limitations, Cursor introduced the Project Rules system based on the
.cursor/rules/ directory. This new approach allows organizing rules into separate files
with structured metadata and conditional activation based on file patterns.
The .cursor/rules/ directory is designed to be committed to the git repository so that
all team members automatically share the same AI instructions. Each file in the directory is an
.mdc (Markdown with Context) file containing a YAML frontmatter and the instruction body
in Markdown.
Why .mdc and Not .md?
The .mdc (Markdown with Context) format is a Cursor-proprietary extension that adds
structured frontmatter to standard Markdown. The frontmatter defines metadata such as the rule
description, glob patterns for automatic activation, and the alwaysApply flag. Cursor
interprets these metadata to decide when and how to apply each rule.
The Four Rule Types
Cursor's modern system defines four activation modes for rules, each designed for a specific use case. Choosing the right type is crucial to balancing instruction relevance with AI context consumption.
1. Always Rules
Always rules are included in every AI interaction, regardless of the file you are working on or the request you make. They are ideal for universal project conventions that must always be respected.
---
description: Global project conventions
alwaysApply: true
---
# Project Conventions
## Language
- Always respond in English
- Write code comments in English
- Variables and functions in English (camelCase)
## Architecture
- Pattern: Feature-based folder structure
- State management: Signals (Angular) / Zustand (React)
- Testing: Every module must have > 80% coverage
## Git
- Commit messages in conventional commits format
- Prefixes: feat, fix, refactor, docs, test, chore
- Branch naming: feature/xxx, bugfix/xxx, hotfix/xxx
Watch Your Context Budget
Always rules are always sent to the AI, consuming context tokens in every interaction. Use this type only for truly universal rules. If a rule applies only to certain files or situations, prefer Auto Attached or Agent Requested to optimize context usage.
2. Auto Attached Rules
Auto Attached rules are automatically activated when you work on files that match specific glob patterns. They are perfect for language-specific, framework-specific, or file-type-specific rules.
---
description: Rules for Angular components
globs: ["**/*.component.ts", "**/*.component.html"]
alwaysApply: false
---
# Angular Components
## Structure
- ALWAYS use standalone components (no NgModule)
- Implement OnPush change detection strategy
- Prefer signals() and computed() for reactive state
- Use input() and output() signal-based (not @Input/@Output decorators)
## Template
- Use the new control flow syntax: @if, @for, @switch
- Prefer @defer for lazy loading heavy sections
- Never use ngIf, ngFor, ngSwitch (legacy)
## Naming
- Files: kebab-case (e.g., user-profile.component.ts)
- Selector: app- prefix (e.g., app-user-profile)
- Class: PascalCase (e.g., UserProfileComponent)
The globs field supports standard glob patterns. You can use simple wildcards like *.ts
or complex patterns like {**/*.service.ts,**/*.guard.ts}. When you open a file
matching the pattern, the rule is automatically included in the AI context.
3. Agent Requested Rules
Agent Requested rules are visible to the AI through their description, but are only included in the context when the agent determines they are relevant to the current task. This type is ideal for specialized knowledge that is not always needed but that the AI should be able to consult when necessary.
---
description: Rules for creating and managing database migrations with Prisma
alwaysApply: false
---
# Database Migrations
## Creating Migrations
- Always use `prisma migrate dev --name change-description`
- Migration names: snake_case, descriptive (e.g., add_user_roles_table)
- NEVER modify migrations already applied in production
## Prisma Schema
- Every model must have: id, createdAt, updatedAt
- Use @@map for snake_case table names
- Relations: always define both sides
- Indexes: add @@index for fields used in WHERE and JOIN
## Rollback
- Always test rollback before applying to staging
- Document required manual steps in the migration file
In this example, the rule has no globs and has alwaysApply: false. The AI will
only see the description "Rules for creating and managing database migrations with Prisma" and will
autonomously decide whether to include the full rule content when the task involves database operations.
This approach is particularly efficient: the AI has access to a catalog of specialized knowledge without
wasting context when it is not needed.
4. Manual Rules
Manual rules are never included automatically. They must be explicitly invoked by the
developer using the @ruleName reference in the prompt. They are useful for templates,
snippets, or instructions you only want to use in specific situations.
---
description: Template for creating a complete new Angular feature
alwaysApply: false
---
# New Feature Template
When creating a new Angular feature, generate the following files:
## Directory Structure
```
src/app/features/[feature-name]/
[feature-name].component.ts # Main component
[feature-name].component.html # Template
[feature-name].component.css # Styles
[feature-name].component.spec.ts # Component tests
[feature-name].service.ts # Data service
[feature-name].service.spec.ts # Service tests
[feature-name].routes.ts # Lazy-loaded routing
[feature-name].model.ts # Interfaces and types
```
## Checklist
- [ ] Standalone component with OnPush
- [ ] Service with HttpClient and error handling
- [ ] Lazy-loaded route registered in app.routes.ts
- [ ] Unit tests for component and service
- [ ] Interfaces for data models
To use this rule, the developer would write something like: "Create a new user profile feature following @new-feature-template". The AI will include the rule content in the context and generate code according to the template.
Rule Types Summary
| Type | Activation | Use Case | Context Cost |
|---|---|---|---|
| Always | Always included | Universal project conventions | High (always active) |
| Auto Attached | File glob pattern | Language/framework-specific rules | Medium (only relevant files) |
| Agent Requested | AI decides based on description | On-demand specialized knowledge | Low (only when needed) |
| Manual | Explicit invocation with @name | Templates, snippets, rare instructions | Minimal (only on demand) |
User Rules vs Project Rules
Cursor distinguishes between two configuration levels: User Rules that apply to all your projects and Project Rules that are specific to a single repository. Understanding when to use each is fundamental for an effective setup.
User Rules: Your Global Preferences
User Rules are configured in Cursor Settings > General > Rules for AI. These rules
define your personal preferences that remain consistent regardless of the project you are working on.
They are not files in the repository: they live in Cursor's local configuration.
## General Preferences
- Always respond in English for explanations
- Write code comments in English
- When generating code, always include error handling
- Prefer immutability: create new objects instead of mutating existing ones
- Use TypeScript strict mode in all TypeScript projects
- Follow SOLID principles and clean code practices
- When suggesting solutions, explain the reasoning
## Preferred Format
- Short functions (<50 lines)
- Focused files (<400 lines)
- Maximum nesting: 4 levels
- Explicit and descriptive naming
Project Rules: Repository Conventions
Project Rules live in the .cursor/rules/ directory and are committed to the git repository.
This means every team member who clones the repo will automatically have the same AI instructions,
ensuring consistency in code generation.
User Rules vs Project Rules: When to Use What
| Aspect | User Rules | Project Rules |
|---|---|---|
| Scope | All projects | Single repository |
| Location | Cursor Settings | .cursor/rules/*.mdc |
| Sharing | Local only | Via git (team) |
| Precedence | Base (overridden by project) | High (context-specific) |
| Example | Language, response style, general principles | Framework, architecture, specific patterns |
Precedence works intuitively: Project Rules take priority over User Rules when there is a conflict. If your User Rules say "use classes" but the Project Rules say "use functions", the AI will follow the Project Rules. This allows each project to have its own conventions without needing to modify global preferences.
Anatomy of an Effective Rule
Writing a rule that the AI can correctly follow requires attention to structure, clarity, and specificity of instructions. A well-written rule is the difference between an AI that generates generic code and an AI that generates code perfectly aligned with your standards.
.mdc File Structure
Each .mdc file is composed of two parts: the YAML frontmatter delimited
by --- and the Markdown body with the actual instructions.
---
description: [Concise description for AI - used for Agent Requested]
globs: ["pattern1", "pattern2"]
alwaysApply: true|false
---
# Rule Title
## Section 1: General Instructions
- Clear and specific instruction
- Concrete example if needed
## Section 2: Patterns to Follow
- Preferred pattern with example
- Anti-pattern to avoid with explanation
## Section 3: Exceptions
- When NOT to apply these rules
- Edge cases and how to handle them
Best Practices for Writing Effective Rules
After configuring hundreds of rules in real projects, I have identified five fundamental principles that determine a rule's effectiveness.
1. Be specific, not generic. A rule that says "write clean code" is useless. A rule that says "every function must have at most 4 parameters, each with explicit type and JSDoc" is actionable by the AI.
2. Show, do not just tell. Always include at least one concrete code example that follows the rule. The AI learns better from examples than from abstract descriptions.
3. Define anti-patterns too. Explicitly state what NOT to do. If the rule says "use signals" but does not say "do not use BehaviorSubject," the AI might mix both approaches.
4. One rule, one theme. Do not create monolithic files that cover everything. Split rules by area: one rule for testing, one for CSS, one for architecture. This simplifies maintenance and enables selective activation through globs.
5. Write the description thinking like the AI. The description field
in the frontmatter is what the AI reads to decide whether to include an Agent Requested rule. It
must be concise but informative enough for the AI to understand when the rule is relevant.
Angular Rules: Complete Example
Angular is a framework with precise conventions and a rapidly evolving ecosystem. With the transition to standalone components, signals, and the new control flow syntax, it is critical that the AI generates code following modern best practices. Here is a complete rule set for an Angular project.
---
description: General architecture and patterns for the Angular project
alwaysApply: true
---
# Angular Architecture
## Version and Stack
- Angular 19+ with standalone components
- TypeScript 5.7+ in strict mode
- State: Angular Signals (signal, computed, effect)
- HTTP: HttpClient with functional interceptors
- Routing: Lazy loading with loadComponent/loadChildren
## Folder Structure
```
src/app/
core/ # Singleton services, guards, interceptors
shared/ # Shared components, pipes, directives
features/ # Feature modules (one folder per feature)
feature-a/
components/
services/
models/
feature-a.routes.ts
layouts/ # Layout components (header, footer, sidebar)
```
## Principles
- NO NgModule: everything standalone
- Lazy loading for every feature route
- Services in core/ provided in root (providedIn: 'root')
- Shared components in shared/ with no business logic
- One component = one .ts + .html + .css + .spec.ts file
---
description: Rules for Angular Signals usage and reactivity
globs: ["**/*.component.ts", "**/*.service.ts"]
alwaysApply: false
---
# Angular Signals
## Reactive State
- USE: signal() for component local state
- USE: computed() for derived values
- USE: effect() ONLY for side effects (logging, localStorage)
- DO NOT USE: BehaviorSubject for local state
- DO NOT USE: getters with complex logic (use computed instead)
## Signal-based Input/Output
- USE: input() and input.required() for inputs
- USE: output() for events
- DO NOT USE: @Input() and @Output() decorators (deprecated)
- USE: model() for two-way binding
## Correct Example
```typescript
export class UserCardComponent {
// Signal-based input
readonly user = input.required<User>();
readonly showAvatar = input(true);
// Computed from input
readonly displayName = computed(() =>
`






