Cursor Rules vs DESIGN.md — What Goes Where?
You set up .cursorrules. You get consistent code style, proper naming conventions, your preferred patterns. Then someone tells you about DESIGN.md. You look at it and think: “Wait — isn’t this what my cursor rules already do?”
No. They solve different problems. And the confusion is costing you either visual inconsistency or bloated rule files that try to do everything.
Here’s the clean split.
What .cursorrules Actually Does
Your .cursorrules file (or .cursor/rules/*.mdc) tells the agent how to behave. It’s behavioral. Think of it as the agent’s personality and work habits.
What belongs there:
- Code style — “Use TypeScript strict mode,” “Prefer named exports,” “No default exports”
- Patterns — “Use server actions for mutations,” “All API calls go through
/lib/api” - Tone — “Write terse commit messages,” “Comments explain why, not what”
- Guardrails — “Never modify
package.jsonwithout asking,” “Don’t delete test files” - Architecture — “Follow the feature-folder pattern,” “Each route is a directory with
page.tsx+layout.tsx”
Notice the pattern: all of these are about behavior. How the agent writes code. What conventions it follows. Where things go.
A good .cursorrules makes the agent write code like you would. It doesn’t tell the agent what your buttons look like.
What DESIGN.md Does
DESIGN.md tells the agent what to design. It’s a reference document. Think of it as the design system your agent consults before touching any UI.
What belongs there:
- Color tokens — primary, surface, accent, semantic colors with exact hex values
- Typography — font families, size scale, weight mappings
- Spacing — your grid system, padding/margin values
- Component specs — “Cards use 1px border, 12px radius, 24px padding”
- Visual rules — “Never mix sharp and rounded corners,” “Maximum 3 font sizes per page”
- Do’s and Don’ts — visual constraints specific to your brand
Notice this pattern: all visual. All about what the output looks like. Not about how the agent gets there.
A good DESIGN.md makes every generated component look like it belongs in your app. Regardless of which agent generates it.
The Architectural Split
Here’s the mental model that makes this click:
| .cursorrules | DESIGN.md | |
|---|---|---|
| Controls | Agent behavior | Visual output |
| Answers | ”How should I write code?" | "What should this look like?” |
| Changes when | Your workflow changes | Your design changes |
| Scope | All code generation | UI/visual generation only |
| Portable | No (Cursor-specific) | Yes (any agent reads it) |
That last row matters. Your .cursorrules is locked to Cursor. Switch to Claude Code tomorrow and it’s useless — you’d need a CLAUDE.md instead. But DESIGN.md works everywhere. Claude Code, Kiro, Windsurf, Copilot — they all read Markdown. One file, every agent.
The split is also about change frequency. Your cursor rules stabilize fast — once you nail your preferences, they barely change. Your design system evolves constantly. New components, updated colors, adjusted spacing. Keeping them separate means updating one doesn’t risk breaking the other.
The Practical Setup
Here’s what a well-structured project looks like:
my-project/
├── DESIGN.md ← Visual system (portable)
├── .cursor/
│ └── rules/
│ ├── general.mdc ← Code behavior
│ └── design-system.mdc ← Bridge (points to DESIGN.md)
├── src/
└── ...
Your design-system.mdc is the bridge between the two worlds:
---
description: Design system enforcement
globs: ["**/*.tsx", "**/*.jsx", "**/*.vue", "**/*.svelte", "**/*.css"]
---
Before generating any visual component, read @DESIGN.md and follow it exactly.
- Use ONLY colors from DESIGN.md tokens
- Follow the typography scale — no invented sizes
- Apply spacing from the defined grid
- Match component patterns from the Components section
- Never violate Do's and Don'ts
That @DESIGN.md reference is the key. The cursor rule doesn’t contain design decisions — it delegates to the design system file. The rule says “follow the visual spec.” The spec says what the visual spec actually is.
Your general.mdc stays clean and focused on behavior:
---
description: Code conventions
globs: ["**/*.{ts,tsx}"]
---
- TypeScript strict mode, no `any`
- Named exports only
- Server components by default, 'use client' only when needed
- Colocate tests: `thing.test.ts` next to `thing.ts`
No colors. No font sizes. No visual tokens polluting your code rules.
Why This Matters
I’ve seen .cursorrules files that are 400 lines long. Half of it is design system stuff crammed in: hex codes, spacing values, component descriptions. It works — technically. But it’s fragile.
Problems with cramming everything into cursor rules:
- Not portable. Switch editors and you lose your design system context.
- Bloated context. Every prompt loads all rules. Your backend API route doesn’t need to know about button border-radius.
- Hard to maintain. Design tokens change often. Digging through behavioral rules to find a color value is annoying.
- Can’t share. A
.cursorrulesfile is personal. A DESIGN.md can be shared across repos, tools, and team members.
The globs field in .cursor/rules/ already gives you the solution. Design rules only load for UI files. Backend files never see them. But the design content lives in DESIGN.md where any tool can access it.
Getting Started
If you’re already using .cursorrules and want to add DESIGN.md:
- Extract visual rules from your cursor rules into a DESIGN.md file. Colors, fonts, spacing, component patterns — move them out.
- Get a DESIGN.md from the library if you’re starting fresh, or create your own.
- Add a bridge rule that tells Cursor to read DESIGN.md for UI work.
- Follow the full Cursor setup guide for glob patterns, advanced patterns, and troubleshooting.
The migration takes 15 minutes. Your cursor rules get shorter and more focused. Your design system becomes portable. Every UI component gets consistent.
The One-Sentence Version
.cursorrules defines how your agent thinks — DESIGN.md defines what it sees.
Use both.