기본 콘텐츠로 건너뛰기

Migrating .cursorrules to .cursor/rules: A Token Diet

💡 Key Takeaways: Token Diet with .mdc Rules
  • Monolithic .cursorrules Bloat: Loading a single large rule file consumes 1,500–3,000 extra tokens per prompt and causes rule collisions across unrelated languages.
  • Directory Scoping: Migrating to individual .cursor/rules/*.mdc files leverages targeted globs, semantic description matching, and on-demand manual triggering.
  • 80% Overhead Cut: Scoped rules load only when relevant files or intents match, drastically preserving context window space and preventing instruction drift.

You added a new rule to .cursorrules last sprint: "always use Zod for validation." Now Cursor is trying to slap Zod schemas onto your Go microservice's YAML config files. That's not a hallucination — that's your monolithic rules file doing exactly what you told it to do, everywhere, all the time.

If you've been staring at a bloated .cursorrules file wondering why the agent keeps ignoring half your instructions while stubbornly following the other half in the wrong context, you're not imagining things. Cursor has quietly deprecated the single-file format in favor of a scoped, directory-based system — .cursor/rules/*.mdc — and the difference in agent behavior is night and day.

This is an engineering migration guide, not a vague feature announcement. We'll break down the .mdc schema, walk through a real repository refactor, and share three battle-tested templates you can copy and deploy immediately.

Why the Monolithic .cursorrules File Falls Apart

Think of .cursorrules like a single 2,000-page employee handbook that HR photocopies and hands to every new hire — the barista, the backend engineer, and the facilities manager — regardless of their responsibilities. Everyone has to read the entire manual before doing anything, even the three sentences that actually apply to their shift.

That's precisely what happens on every single prompt turn when you rely on a root-level .cursorrules file. Cursor injects the entire file into context, whether you're editing a React component or a SQL migration script. This legacy approach creates two severe problems:

⚠️ Key Drawbacks of Root-Level Rules:
  • The Token Tax: A 400-line rules file burns 1,500–3,000 tokens per prompt turn before the model even reads your actual code.
  • Instruction Collision: Frontend conventions (Tailwind class ordering, JSX props) get injected into backend tasks, confusing the LLM about which constraints actually apply.

The result is the well-documented "lost in the middle" phenomenon — long-context models pay significantly less attention to instructions buried in the middle of a massive prompt. Cursor's architectural solution is straightforward: split one giant file into targeted, modular .mdc files that load only when relevant.

Anatomy of the .mdc File: Frontmatter + Activation Modes

Every rule now lives in .cursor/rules/ as an individual .mdc file — standard Markdown with a structured YAML frontmatter header. Here is the official schema:

---
description: Standards for React Server Components and UI mutations
globs: ["src/components/**/*.tsx", "src/app/**/*.tsx"]
alwaysApply: false
---

# Rule body goes here in plain Markdown.
Use named exports only. No default exports for components.

Three core frontmatter fields control rule execution:

  • description (string): Summary evaluated semantically by the Cursor Agent to decide if the rule matches the user's intent, even when no glob pattern matches.
  • globs (string or array): Wildcard file path patterns. When matching files are active in the editor or referenced, the rule auto-attaches.
  • alwaysApply (boolean): When true, injects into every session universally. Use this only for foundational repository invariants.

The 4 Activation Modes

Mode Trigger Condition Best Use Case Token Overhead
Always Applied alwaysApply: true Core stack invariants (package manager, monorepo layout) Constant (< 500 tokens recommended)
Glob Scoped Active file path matches globs Domain conventions (frontend components, API routes, DB migrations) Zero when file is not active
Agent-Requested Semantic match on description Cross-cutting concerns (e.g., git commit standards, test setups) Zero until developer intent matches
Manual @rule Explicit @rule-name.mdc in Composer One-off migration scripts, rare audit tasks Zero unless explicitly invoked
(Legacy) .cursorrules Always, unconditionally Deprecated — avoid in new projects Constant & unavoidable tax

Migration Blueprint: 4 Phases

[Phase 1: Audit legacy .cursorrules] ➔ [Categorize: universal vs domain-specific]
  ↓
[Phase 2: Scaffold .cursor/rules/ directory]
  ↓
[Phase 3: Write scoped frontmatter per file]
  ↓
[Phase 4: Verify triggers in Composer] ➔ {Rules firing?} ➔ Yes ➔ [Delete root .cursorrules]

Phase 1: Rule Inventory & Token Auditing

Open your existing .cursorrules and split each block into two categories: universal invariants (package manager, commit style) versus domain-specific rules (React, Prisma, Docker). In most repositories, over 80% of instructions are domain-specific and should never be loaded globally.

Phase 2: Directory Scaffolding

.cursor/
  rules/
    project-core.mdc          # alwaysApply: true, <500 tokens
    react-tailwind.mdc        # globs: src/components/**/*.tsx
    api-routes.mdc            # globs: src/app/api/**/*.ts
    database-migrations.mdc   # alwaysApply: false, agent-requested

Phase 3: Crafting Scoped Frontmatter

Avoid generic catch-all patterns like globs: ["**/*"], which recreate the original monolithic problem. Match specific folders and file extensions precisely:

---
description: API route handler conventions for Next.js App Router
globs: ["src/app/api/**/route.ts", "src/lib/api/**/*.ts"]
alwaysApply: false
---

Phase 4: Verification & Safe Deprecation

In Cursor Composer, type @ to view available rules. Confirm that opening a .tsx file attaches the React rule without injecting database schema rules. Once verified, delete the root .cursorrules file to prevent double-injection.

Three Production-Ready .mdc Templates

Template 1 — Global Core Baseline (project-core.mdc)
---
description: Non-negotiable project-wide invariants
globs: []
alwaysApply: true
---

# Core Standards (always loaded — keep this file lean)

- Package manager: pnpm only. Never suggest npm or yarn commands.
- Monorepo structure: apps/ for deployables, packages/ for shared libs.
- TypeScript strict mode is non-negotiable across all packages.
- Commit messages follow Conventional Commits (feat:, fix:, chore:).
- Never commit secrets or .env files directly to version control.
Template 2 — Scoped Frontend Component Rule (react-tailwind.mdc)
---
description: Standards for React components using Tailwind CSS
globs: ["src/components/**/*.tsx", "apps/web/**/*.tsx"]
alwaysApply: false
---

# React + Tailwind Component Rules

- Use named exports only; no default exports for UI components.
- Order Tailwind utility classes: Layout -> Spacing -> Typography -> Color.
- All interactive buttons and links require an aria-label or visible text.
- Prefer component composition (children props) over deep prop-drilling booleans.
- Encapsulate server-only logic outside of client components marked with "use client".
Template 3 — On-Demand Migration Rule (database-migrations.mdc)
---
description: Guidelines for writing and reviewing database schema migrations
globs: ["db/migrations/**/*.sql", "prisma/migrations/**/*"]
alwaysApply: false
---

# Database Migration Standards

- Every migration script must include a corresponding down/revert migration.
- Never use DROP COLUMN without a two-phase deprecate-then-remove deployment.
- Reference the active schema audit doc before altering foreign key constraints.
- Avoid locking table operations during production traffic peaks.

Token Budget Math: Why Scoping Actually Works

Editing Context Active Rules Loaded Approx. Token Cost per Turn
Legacy .cursorrules (editing Go file) Entire 380-line monolithic file ~2,800 tokens
Scoped .mdc (editing Go file) project-core.mdc only ~400 tokens
Scoped .mdc (editing .tsx file) project-core.mdc + react-tailwind.mdc ~750 tokens
📌 Efficiency Rules for Engineering Teams:
  • Keep individual .mdc files under 150 lines. If a rule exceeds this limit, split it by submodule.
  • Never write globs: ["**/*"] — that recreates the monolithic overhead under a new file extension.
  • Formulate description fields as clear developer queries to ensure reliable semantic agent activation.

Common Migration Questions & Troubleshooting

Q: Can I keep .cursorrules and .cursor/rules/ side by side during migration?

Temporarily during migration, yes. However, remove legacy files once verified, as overlapping rules cause duplicate instructions in prompt contexts.

Q: What if a rule is not firing despite matching the glob pattern?

Check your glob relative paths. Globs in Cursor resolve from the repository workspace root. If your project is inside a subfolder, specify apps/web/src/**/*.tsx instead of src/**/*.tsx.

Q: Do monorepo packages need nested .cursor/rules/ folders?

No. Keep a unified .cursor/rules/ folder at the workspace root and use distinct path globs (packages/ui/**, apps/api/**) for modular scoping.

💡 Next Steps & Action Items

Audit your current .cursorrules file this week. Split it by domain, write tight globs, and reserve alwaysApply: true for global constraints.

For more deep dives on agent configurations and LLM engineering patterns, explore our comprehensive LLM & CODE guide category.

댓글

이 블로그의 인기 게시물

Gemini Many-Shot Prompting: Why 500 Examples Beat Fine-Tuning

No More Git Conflicts: Automate PR Reviews with Cline

기밀 유출 없는 DeepSeek R1 무료 로컬 실행법