Custom Instructions with Cursor Rules
Custom Instructions with Cursor Rules
One of Cursor's most powerful but underutilized features is its rules system. Rather than re-explaining your coding preferences in every chat session, you can write them down once and have every AI interaction in your project automatically follow them. The result is an AI collaborator that sounds like it knows your codebase — because you taught it how.
In this lesson, you will learn what Cursor Rules are, how to write them, and how to use them to make every AI response more useful and consistent.
What You'll Learn
- What
.cursorrulesfiles are and how they work - The difference between project-level rules and global rules
- How rules shape AI behavior across chat, Cmd+K, and Tab completion
- How to structure the
.cursor/rulesdirectory with multiple rule files - Writing effective rules with concrete examples
- Best practices for rule format and organization
- When and how to update your rules as a project evolves
What Are Cursor Rules?
Cursor Rules are plain-text instruction files that you write to tell Cursor's AI how to behave in your project. Think of them as a persistent system prompt — a set of guidelines the AI reads before every interaction, so you never have to repeat yourself.
Without rules, each chat session starts fresh. The AI does not know whether your project uses TypeScript strict mode, whether you prefer async/await over promise chains, or whether every function should include error handling. With rules, all of that context is always present.
Rules influence every AI feature in Cursor:
- Chat (Cmd+L) — The AI follows your rules when answering questions and generating code
- Inline edit (Cmd+K) — Edits respect your style guidelines and conventions
- Tab completion — Suggestions align with patterns you have specified
- Agent mode — Multi-step tasks stay consistent with your architecture rules
A Simple Example
Consider a project where you always want functional React components with TypeScript. Without rules, the AI might generate a class component, or a component without type annotations, depending on what it guesses you want. With a single rule:
Always use functional React components with TypeScript.
Never use class components.
All component props must have explicit TypeScript interfaces.
Every suggestion the AI makes will follow this pattern from that point on.
Project-Level Rules vs Global Rules
Cursor supports two levels of rules:
Project-Level Rules
Project-level rules live inside your project directory and apply only to that project. They are checked into your repository, so every team member who uses Cursor automatically gets the same AI behavior.
There are two ways to create project-level rules:
1. The .cursorrules file (original format)
Create a file named .cursorrules at the root of your project:
my-project/
├── .cursorrules ← project-level rules here
├── src/
├── package.json
└── ...
This single file contains all your rules as plain text. It is simple and effective for smaller projects.
2. The .cursor/rules/ directory (newer format)
For more complex projects, Cursor supports a directory of separate rule files:
my-project/
├── .cursor/
│ └── rules/
│ ├── general.mdc ← general coding standards
│ ├── react.mdc ← React-specific rules
│ ├── typescript.mdc ← TypeScript rules
│ └── testing.mdc ← testing conventions
├── src/
└── package.json
Rule files in this directory use the .mdc extension and support metadata at the top for controlling when each rule file applies. This lets you keep rules organized and only load relevant rules for the current context.
Global Rules
Global rules apply to all projects in Cursor. You configure them in Cursor's settings under Cursor Settings → Rules for AI. These are stored locally and not checked into any repository.
Global rules are good for personal preferences that apply everywhere — your preferred comment style, your preferred variable naming conventions, or reminders about how you like explanations formatted.
Which Takes Priority?
Project-level rules and global rules are combined. The AI sees both. If there is a conflict, project-level rules generally take precedence because they are more specific.
How Rules Shape AI Behavior
Rules work by being injected into the context window for every AI interaction. When you open a chat, Cursor reads your rules and passes them to the model before your message. The model then uses those rules as constraints when generating its response.
This means rules affect:
- Code style — indentation, quote style, semicolons, line length
- Framework patterns — which hooks to use, how to structure components
- Language features — which TypeScript features to use or avoid
- Architecture decisions — where to put logic, how to organize files
- Error handling — whether to throw, return error objects, or use try/catch
- Documentation — whether to add JSDoc comments, how verbose they should be
- Testing — which testing library, how to name tests, what to test
The AI does not blindly follow rules as hard constraints — it uses them as guidance. If a rule conflicts with what you are asking for, you can always override it in your chat message. Rules set defaults; your prompts have the final say.
Writing Effective Rules
Good rules are specific, actionable, and unambiguous. Vague rules like "write clean code" do not help because every AI already tries to write clean code. Specific rules like "use const instead of let unless reassignment is required" give the AI clear guidance.
Principles for Good Rules
Be concrete, not aspirational. Instead of "write maintainable code," write "extract functions that are longer than 30 lines into separate named functions."
Specify the why when it helps. "Prefer Array.map() over for loops for transformations — this project uses a functional style" is more useful than just "use Array.map()."
Include examples where ambiguous. For unusual patterns, a short example prevents misinterpretation.
Keep rules focused. One rule per concern. Do not combine "use TypeScript strict mode and always add error handling and prefer functional components" into a single rule — break it into three.
Examples of Effective Rules
Here is a set of rules for a modern TypeScript/React project:
# Language and Types
- Use TypeScript strict mode. Never use `any` type. Use `unknown` when the type is truly uncertain.
- Prefer type aliases over interfaces for object shapes. Use interfaces only for extensible public APIs.
- All function parameters and return values must have explicit type annotations.
# React Components
- Use functional components with React hooks. Never use class components.
- All component props must have a named TypeScript type defined directly above the component.
- Extract reusable logic into custom hooks in src/hooks/. Name custom hooks with the `use` prefix.
- Keep components under 150 lines. If longer, split into subcomponents.
# Error Handling
- All async functions must have try/catch blocks or return a Result type.
- Never swallow errors silently. Always log or propagate them.
- Use custom error classes for domain errors in src/errors/.
# API and Data Fetching
- Use React Query for all server state. Do not use useEffect for data fetching.
- API calls go in src/api/. Components should call hooks, not API functions directly.
# Testing
- Use Vitest and React Testing Library. No Enzyme.
- Test files live next to the files they test, named *.test.ts or *.test.tsx.
- Test behavior, not implementation. Do not test internal state.
These rules are specific enough to meaningfully change what the AI generates, while leaving room for judgment on matters that depend on context.
The .cursor/rules/ Directory Format
When your project grows, a single .cursorrules file can become unwieldy. The .cursor/rules/ directory lets you split rules into separate files with metadata that controls when each file is active.
Rule File Format
Each .mdc file can have a frontmatter header:
---
description: React component conventions
globs: ["src/components/**/*.tsx", "src/pages/**/*.tsx"]
alwaysApply: false
---
# React Component Rules
- Use functional components with TypeScript
- Define prop types as named interfaces above each component
- Use the shadcn/ui component library for UI primitives
The globs field means this rule file only activates when you are working on files that match those patterns. Your testing rules only apply when editing test files. Your API rules only apply when in the src/api/ directory.
The alwaysApply field forces a rule to be active regardless of the current file context. Use this for rules that should always be in effect — like your general TypeScript conventions.
Organizing Rules by Concern
A well-organized .cursor/rules/ directory might look like this:
.cursor/rules/
├── general.mdc # Always applies: language, style, error handling
├── react.mdc # Applies to *.tsx files
├── api.mdc # Applies to src/api/**
├── tests.mdc # Applies to *.test.ts, *.spec.ts
├── database.mdc # Applies to src/db/** or *.sql
└── styles.mdc # Applies to *.css, *.module.css
This structure keeps your rules focused and prevents the AI from being overloaded with irrelevant context.
When to Update Your Rules
Rules are living documentation. They should evolve alongside your project.
Add rules when you notice repeated corrections
If you find yourself telling the AI the same thing in multiple chat sessions — "don't forget to handle the loading state," "always check for null before accessing this property" — that is a signal to add a rule.
Update rules when the project changes direction
If your team decides to migrate from one testing library to another, update the rules immediately. Stale rules that reference outdated patterns can actively confuse the AI.
Review rules when onboarding team members
Rules double as documentation for your team. When a new developer joins and asks "how do we handle errors here?" you can point them to your rules file. This makes rules more valuable to maintain carefully.
Remove rules that no longer apply
Outdated rules create noise. If your project no longer uses a particular pattern or library, remove the rules that reference it. The cleaner your rules, the more reliable the AI's behavior.
Summary
Cursor Rules let you encode your project's conventions, style guidelines, and architectural decisions into plain-text instruction files that the AI reads automatically. A .cursorrules file at the root of your project is the simplest way to start. For larger projects, the .cursor/rules/ directory with .mdc files gives you fine-grained control over which rules apply in which contexts.
The investment in writing good rules pays off quickly. Once you have rules in place, you stop correcting the AI and start reviewing its output.
Key Takeaways
- Cursor Rules are plain-text instruction files that give the AI persistent guidance for every interaction in your project
- Project-level rules live in
.cursorrulesor.cursor/rules/and are checked into your repository so the whole team benefits - Global rules in Cursor Settings apply across all projects and capture personal preferences
- Effective rules are specific and actionable — concrete coding standards, not vague aspirations
- The
.cursor/rules/directory allows separate rule files with glob patterns so rules only activate for relevant files - Rules should evolve with your project: add them when you notice repeated corrections, update them when the project changes, and remove stale ones
Quiz
Discussion
Sign in to join the discussion.

