Building a Multi-Level Cursor Rules System: Global vs. Repository
You know that moment when your AI coding assistant suddenly forgets everything you taught it? You’re deep into a React component, ask Cursor to generate a form, and it produces class components, ignores your preferred error-handling pattern, and misses your team’s naming conventions completely. I’ve experienced that. That’s when I realized that having just one .cursorrules file at the project root wasn’t enough. What I needed was a multi-level rules system—global preferences that follow me everywhere, along with repo-specific rules that understand each project’s quirks. So let’s explore how to build that system, blending global and repository-level Cursor rules without creating confusion.
How Cursor Rules Actually Work (the short version)
Cursor has evolved from a single .cursorrules file. Now you can create a .cursor/rules directory in any project and fill it with individual .mdc (Markdown with metadata) files. Each file can include a frontmatter block that specifies when the rule applies: always, manually, or automatically based on file types. This is effective because you can break up large rule sets into smaller, purpose-driven files.
Cursor also respects a global rule space. Under Cursor > Settings > General > Rules for AI, there’s a text area for rules that apply to every project. That’s your global layer. Combine this with the repo-level .cursor/rules directory, and you get a two-tier structure that’s flexible, scalable, and easy to maintain once you understand the hierarchy.
Why Bother with Multiple Levels?
I used to keep all my rules globally, thinking, “I want consistency everywhere.” This worked well until I switched from a strict TypeScript backend project to a chaotic freelance WordPress site. My global rules insisted on strict typing, functional components only, and a specific barrel export pattern—all of which were irrelevant in a PHP-heavy, jQuery-loaded codebase. I needed a way to stop Cursor from confusing me into writing import { Button } from ‘@/components’ in a project that didn’t even have a components folder.
A multi-level system allows you to:
- - Set universal coding principles once (global).
- - Override or extend them per project (repo).
- - Keep each rule file small and relevant.
- - Share repo-level rules with the team through version control, while personal preferences remain local in your global settings.
In simple terms, global rules are your personal defaults. Repo rules serve as the project’s agreement.
Setting Up Global Rules That Actually Stick
Open Cursor’s settings and locate the “Rules for AI” box. This is your command center for everything universal. Think of it as the rules you want included in every chat and every Ctrl+K command, no matter what folder you have open.
A common mistake is dumping everything into this area. Don’t do that. The global layer should only contain rules that are truly universal to how you work, not specific to any tech stack. For me, that includes:
- - Response language and tone: “Always reply in English. Be concise. Use ‘please’ only for serious mistakes.”
- - File creation permissions: “Never create new files unless I explicitly ask. Propose changes first.”
- - Coding philosophy: “Prefer readability over cleverness. Avoid ternary operators inside template literals.”
- - Tool usage guidelines: “When suggesting terminal commands, explain what they do before showing the code block.”
These rules will apply whether I’m working on a Next.js app, a Python data pipeline, or even a markdown documentation repository. They focus on the interaction, not the specific domain.
Pro tip: Use markdown formatting in that text area. A well-structured heading hierarchy helps the model understand your global rules faster. I start with a # Global Preferences heading and organize sections underneath.
The Repo Layer: Project-Specific Rules with Attitude
This is where the real magic occurs. Inside your project root, create a .cursor/rules folder. Each rule file is an .mdc file—essentially Markdown with YAML frontmatter between --- markers. The frontmatter specifies when the rule should apply. For instance, a rule that only applies to TypeScript files:
``` --- alwaysApply: false globs: - "**/*.ts" - "**/*.tsx" ---
# TypeScript Conventions - Use interfaces, not types, for object shapes. - Prefer async/await over raw promises. - Export component props as `ComponentNameProps`. ```
You can have multiple files: coding-style.mdc for general code, testing.mdc for test conventions, git-commits.mdc for commit message formats (though the last one serves more as a reminder for you than for the AI, but Cursor can suggest commits as well). The alwaysApply: true files will be included in every request, while glob-based ones load only when editing matching files.
What I love about the repo layer is how it evolves naturally. Start with one file covering the common issues that everyone on the team tends to forget. When that file gets too long, split it. The AI reads each file as a separate chunk of context, so keeping them modular helps avoid overwhelming the context window.
Managing Conflicts Between Global and Repo Rules
Now for the tricky part: what happens when your global rule says “use 2-space indentation,” but a project’s .editorconfig and repo rule demand tabs? Cursor doesn’t have a strict priority system like CSS—both rules get included in the prompt. The model sees all of them and generally tries to follow the most specific or recent instruction, but this isn’t always predictable.
You have a few practical strategies:
- Be clear about precedence. In your global rules, add a line like: “If project-specific rules contradict these global preferences, the project rules take precedence.” Some users find this helpful; it gives the model a clear tiebreaker.
- Avoid overlap whenever possible. Keep global rules focused on interaction style, and let repo rules manage code formatting and architecture. If you never repeat topics, conflicts are rare.
- Use the repo to override globals. If a global rule interferes significantly, include a repo rule that explicitly negates it: “Ignore the global rule about using arrow functions; this project uses normal function declarations.” This is a bit manual but effective.
I’ve found that most friction arises from formatting rules. Instead of relying on Cursor for that, use Prettier and ESLint. Let the AI follow the linter’s guidance by including a rule like “Adhere to the project’s ESLint and Prettier configurations at all times.” This way, you don’t have to duplicate style rules at both levels.
Practical Tips for a Multi-Level Setup
After experimenting with this across several repositories, here’s what I’d suggest:
- Start with a global cursor-rules-global.md in your dotfiles. Write it once, then copy it into Cursor’s settings. Keep it synced with your dotfiles repo to ensure you never lose it.
- For team projects, version control the .cursor/rules directory. This is essential. It makes sure everyone experiences the same AI behavior. If someone wants to avoid your global preferences, they can choose not to copy your global text—repo rules then become the only source of truth.
- Add a “contribution” rule for new team members. Something like “If you need the AI to understand project conventions not yet documented in these rules, propose an addition to this folder.” This crowdsources improvements.
- Use the description field in the frontmatter. Cursor displays rule names in the settings panel, so a brief description helps you remember the purpose of each file. For example, description: React component patterns and prop ordering.
- Test rules gradually. Change one behavior at a time and observe Cursor’s output. If a rule isn’t being followed, try rephrasing it more directly. Sometimes “Always do X” works better than “Prefer X over Y.”
A Real Workflow Example
Let me share a recent scenario. I onboarded onto a Vue 3 project that uses the Composition API with <script setup>, Tailwind, and Vitest. My global rules had a React bias since I mostly work in React. I didn’t want to clutter the team’s repository with my personal React quirks.
So, in my global rules, I kept only: “When generating any code, favor clear variable names over comments. Do not add explanatory comments unless the logic is truly non-obvious.” This is applicable across languages.
Then, in the project’s .cursor/rules, I added:
- vue-conventions.mdc (alwaysApply: true) with rules about <script setup>, defineProps with TypeScript, and the team’s naming pattern for composables. - testing.mdc (globs: **/.test.) instructing Cursor to use Vitest’s describe/it blocks and avoid Jest-specific matchers. - tailwind.mdc (alwaysApply: true) reminding the AI to prioritize utility classes, avoid custom CSS files, and adhere to the project’s breakpoint scale.
The first time I asked Cursor to “create a new data table component,” it generated a perfect Vue SFC, used Tailwind classes I didn’t even know about, and included a test file skeleton—all without a single React import. That felt powerful.
Building a multi-level Cursor rules system is more about good habits than complex configuration: separating personal rules from project-specific ones. Global rules maintain your AI assistant as your tool, no matter which codebase you’re working on. Repo rules ensure the whole team receives consistent, thoughtful, and relevant suggestions. Together, they transform Cursor from a generic pair-programmer into a coworker who truly remembers what you’re creating and how you like to create it.
If you’re still cramming everything into a single .cursorrules file, consider changing your approach.