Cursor Rules vs Claude Code Skills: What's the Difference and When to Use Each
Both customize your AI assistant - but they work differently. A deep technical comparison of .cursorrules, .cursor/rules/, CLAUDE.md, and .claude/skills/ with migration strategies.
Cursor Rules and Claude Skills solve the same problem - teaching AI how to behave in your codebase - but they do it in fundamentally different ways. If you've built up a library of .cursorrules files and are considering Claude Code, or vice versa, this guide breaks down every technical difference and gives you a concrete migration strategy.
This isn't a “which tool is better” article. Both tools are excellent. The question is: how do their customization systems differ, and how do you move instructions between them without losing fidelity?
Format: MDC vs. SKILL.md
Cursor uses a format called MDC (Markdown Configuration). An MDC file combines a YAML-like header with glob patterns that determine when the rule fires. The file extension is .mdc and rules live inside .cursor/rules/at the project root. Each rule can be scoped to specific file types using glob patterns in the header, which means the rule only activates when you're editing files that match.
Claude Code uses SKILL.md files - plain Markdown with optional YAML frontmatter. Skills live in ~/.claude/commands/ for global skills or .claude/commands/at the project root for project-specific ones. Claude loads all skills in the directory at session start - there's no file-type scoping built into the format. Instead, you write trigger phrases or explicit scope instructions in the Markdown body.
Side-by-Side: The Same Rule in Both Formats
Cursor MDC (.cursor/rules/react-components.mdc)
| 1 | --- |
| 2 | description: React component conventions |
| 3 | globs: ["src/**/*.tsx", "src/**/*.jsx"] |
| 4 | alwaysApply: false |
| 5 | --- |
| 6 | |
| 7 | # React Component Rules |
| 8 | |
| 9 | 1. Use functional components with arrow syntax |
| 10 | 2. Props interface must be named {ComponentName}Props |
| 11 | 3. Export components as named exports, not default |
| 12 | 4. Place hooks at the top of the component body |
| 13 | 5. Destructure props in the function signature |
| 14 | 6. Use `cn()` from @/lib/utils for conditional classes |
| 15 | |
| 16 | ## Don't |
| 17 | - Don't use React.FC - it adds children implicitly |
| 18 | - Don't inline complex logic in JSX - extract to variables |
| 19 | - Don't use index as key in mapped lists |
Claude SKILL.md (~/.claude/commands/react-components.md)
| 1 | --- |
| 2 | name: react-components |
| 3 | description: React component conventions for TSX/JSX files |
| 4 | version: 1.0.0 |
| 5 | tags: [react, components, style] |
| 6 | --- |
| 7 | |
| 8 | # React Component Rules |
| 9 | |
| 10 | Apply when editing .tsx or .jsx files in src/. |
| 11 | |
| 12 | ## Steps |
| 13 | 1. Use functional components with arrow syntax |
| 14 | 2. Name props interface as {ComponentName}Props |
| 15 | 3. Export as named exports, not default |
| 16 | 4. Place hooks at the top of the component body |
| 17 | 5. Destructure props in the function signature |
| 18 | 6. Use `cn()` from @/lib/utils for conditional classes |
| 19 | |
| 20 | ## Triggers |
| 21 | - "create a component" |
| 22 | - "new react component" |
| 23 | - "refactor this component" |
| 24 | |
| 25 | ## Don't |
| 26 | - Don't use React.FC - it adds children implicitly |
| 27 | - Don't inline complex logic in JSX |
| 28 | - Don't use index as key in mapped lists |
Directory Structure and Loading Behavior
Cursor's rule system is hierarchical. Rules in .cursor/rules/ are project-scoped by default. You can nest them in subdirectories for organization. The glob pattern in the header controls activation: a rule with globs: ["**/*.py"] only fires when you're working with Python files. Rules with alwaysApply: true load into every conversation regardless of file context.
Claude Code uses a flat loading model. Every file in ~/.claude/commands/ (global) and .claude/commands/ (project) is available as a slash command. The user invokes skills explicitly with /skill-nameor the AI matches trigger phrases. There's no automatic file-type gating - you handle scope in the skill's instructions.
| Feature | Cursor Rules | Claude Skills |
|---|---|---|
| File format | .mdc (Markdown Configuration) | .md (plain Markdown + YAML) |
| Location (project) | .cursor/rules/ | .claude/commands/ |
| Location (global) | ~/.cursor/rules/ (Cursor Settings) | ~/.claude/commands/ |
| File scoping | Glob patterns in header | Manual scope in instructions |
| Auto-activation | alwaysApply: true/false + globs | Trigger phrases in body |
| Loading model | Conditional (glob match) | Flat (all loaded, user invokes) |
| Invocation | Automatic when glob matches | Slash command or trigger match |
| Nesting | Subdirectories supported | Flat directory preferred |
| Versioning | Not built-in | version field in frontmatter |
| Max size | ~8K tokens practical limit | ~6K tokens practical limit |
Glob Patterns: Cursor's Killer Feature
Cursor's glob-based activation is genuinely powerful. You can write a rule that only fires for test files (**/*.test.ts), or only for database migrations (db/migrations/*.sql), or only for API routes (src/app/api/**/*.ts). This means your AI assistant automatically switches behavior based on what file you're editing.
Claude Code doesn't have this. You can approximate it by writing “Only apply this skill when working with .test.ts files” in the instructions, but the AI might still reference the skill in unrelated contexts. The tradeoff is simplicity: Claude's model is easier to reason about, while Cursor's is more precise.
| 1 | # Cursor: multiple glob patterns for a testing rule |
| 2 | --- |
| 3 | description: Testing conventions for Jest/Vitest |
| 4 | globs: |
| 5 | - "**/*.test.ts" |
| 6 | - "**/*.test.tsx" |
| 7 | - "**/*.spec.ts" |
| 8 | - "**/__tests__/**" |
| 9 | alwaysApply: false |
| 10 | --- |
| 11 | |
| 12 | # Testing Rules |
| 13 | When writing tests, follow these conventions... |
| 14 | |
| 15 | # Claude: equivalent scope instruction |
| 16 | --- |
| 17 | name: testing-conventions |
| 18 | description: Testing conventions for Jest/Vitest |
| 19 | version: 1.0.0 |
| 20 | tags: [testing, jest, vitest] |
| 21 | --- |
| 22 | |
| 23 | # Testing Rules |
| 24 | **Scope:** Only apply when working with test files |
| 25 | (*.test.ts, *.test.tsx, *.spec.ts, __tests__/). |
| 26 | |
| 27 | When writing tests, follow these conventions... |
When to Use Project Rules vs. Global Skills
Both tools support project-level and global-level configuration, but the use cases differ. Project rules should encode project-specific conventions: your naming patterns, your directory structure, your tech stack choices. Global skills should encode universal practices: how you write commits, how you review code, how you structure documentation.
Project-Level (both tools)
- • Tech stack conventions ("we use Prisma, not Drizzle")
- • Directory structure rules ("API routes go in src/app/api/")
- • Component library usage ("use shadcn, not Material UI")
- • Error handling patterns specific to the project
- • Database schema conventions
- • Environment variable naming
Global-Level (both tools)
- • Code review checklist
- • Git commit message format
- • Documentation writing style
- • Test coverage requirements
- • Security audit patterns
- • Personal coding preferences
Migration Strategy: Cursor Rules to SKILL.md
If you have a working set of Cursor rules and want to use them in Claude Code (or any SKILL.md-compatible tool), here's a systematic approach. The conversion isn't just a format change - you need to rethink activation strategy since Claude doesn't have glob-based triggering.
Step 1: Inventory Your Rules
List all your Cursor rules and classify them. Rules with alwaysApply: true are the easiest to migrate - they map directly to Claude skills that load every session. Rules with glob patterns need trigger phrases to replace the automatic activation.
| 1 | # Run this in your project root to inventory rules |
| 2 | ls -la .cursor/rules/ |
| 3 | # Output example: |
| 4 | # react-components.mdc (globs: src/**/*.tsx) |
| 5 | # testing.mdc (globs: **/*.test.ts) |
| 6 | # api-design.mdc (globs: src/app/api/**) |
| 7 | # general-style.mdc (alwaysApply: true) |
| 8 | # git-commits.mdc (alwaysApply: true) |
Step 2: Convert the Header
Transform the MDC header into SKILL.md frontmatter. The glob patterns become a scope instruction in the body, and you add a version number.
Before (MDC)
| 1 | --- |
| 2 | description: API route conventions |
| 3 | globs: ["src/app/api/**/*.ts"] |
| 4 | alwaysApply: false |
| 5 | --- |
After (SKILL.md)
| 1 | --- |
| 2 | name: api-route-conventions |
| 3 | description: API route conventions for Next.js |
| 4 | version: 1.0.0 |
| 5 | tags: [api, nextjs, routes] |
| 6 | --- |
| 7 | |
| 8 | **Scope:** Apply when working with files |
| 9 | in src/app/api/. |
Step 3: Add Trigger Phrases
Since Claude doesn't auto-activate based on file type, add triggers that map to the situations where the rule would have fired in Cursor. Think about what the developer would say when they need this skill.
| 1 | ## Triggers |
| 2 | - "create an API route" |
| 3 | - "new endpoint" |
| 4 | - "add a route handler" |
| 5 | - "build the API for" |
| 6 | - "REST endpoint for" |
Step 4: Add Structure Claude Expects
Cursor rules tend to be free-form paragraphs. Claude skills perform better with explicit sections: Steps (numbered), Examples (input/output pairs), Triggers, and Don't. If your Cursor rule is a block of text, restructure it.
| 1 | # Before: Cursor free-form style |
| 2 | Use functional components. Always define a Props interface. |
| 3 | Export as named exports. Put hooks at the top. Use cn() for |
| 4 | conditional classes. Don't use React.FC. |
| 5 | |
| 6 | # After: Claude structured style |
| 7 | ## Steps |
| 8 | 1. **Define props interface** - Name it {ComponentName}Props |
| 9 | 2. **Use arrow function** - export const MyComponent = () => {} |
| 10 | 3. **Place hooks first** - all useState/useEffect at top |
| 11 | 4. **Use cn()** - import from @/lib/utils for conditional classes |
| 12 | |
| 13 | ## Examples |
| 14 | ### Input: "Create a button component" |
| 15 | ### Expected output: |
| 16 | ```tsx |
| 17 | interface ButtonProps { |
| 18 | label: string; |
| 19 | variant?: "primary" | "secondary"; |
| 20 | onClick: () => void; |
| 21 | } |
| 22 | |
| 23 | export const Button = ({ label, variant = "primary", onClick }: ButtonProps) => { |
| 24 | return ( |
| 25 | <button className={cn("px-4 py-2", variant === "primary" && "bg-blue-500")} onClick={onClick}> |
| 26 | {label} |
| 27 | </button> |
| 28 | ); |
| 29 | }; |
| 30 | ``` |
| 31 | |
| 32 | ## Don't |
| 33 | - Don't use React.FC |
| 34 | - Don't use default exports for components |
Step 5: Batch Convert with a Script
For teams with 10+ Cursor rules, manual conversion is tedious. Here's a bash script that handles the mechanical parts - header conversion and file renaming. You'll still need to manually add triggers and examples, but the script saves 5-10 minutes per rule on the boilerplate.
| 1 | #!/bin/bash |
| 2 | # convert-cursor-to-skill.sh |
| 3 | # Usage: ./convert-cursor-to-skill.sh .cursor/rules/ output/ |
| 4 | |
| 5 | INPUT_DIR="${1:-.cursor/rules}" |
| 6 | OUTPUT_DIR="${2:-.claude/commands}" |
| 7 | |
| 8 | mkdir -p "$OUTPUT_DIR" |
| 9 | |
| 10 | for file in "$INPUT_DIR"/*.mdc; do |
| 11 | [ -f "$file" ] || continue |
| 12 | basename=$(basename "$file" .mdc) |
| 13 | outfile="$OUTPUT_DIR/$basename.md" |
| 14 | |
| 15 | echo "Converting $file -> $outfile" |
| 16 | |
| 17 | # Extract description from MDC header |
| 18 | desc=$(grep "^description:" "$file" | sed 's/description: //') |
| 19 | globs=$(grep "^globs:" "$file" | sed 's/globs: //') |
| 20 | |
| 21 | # Write SKILL.md header |
| 22 | cat > "$outfile" << EOF |
| 23 | --- |
| 24 | name: $basename |
| 25 | description: $desc |
| 26 | version: 1.0.0 |
| 27 | tags: [migrated-from-cursor] |
| 28 | --- |
| 29 | |
| 30 | EOF |
| 31 | |
| 32 | # Add scope line if globs existed |
| 33 | if [ -n "$globs" ]; then |
| 34 | echo "**Scope:** Apply when working with files matching $globs" >> "$outfile" |
| 35 | echo "" >> "$outfile" |
| 36 | fi |
| 37 | |
| 38 | # Copy body (everything after the closing ---) |
| 39 | sed -n '/^---$/,/^---$/!p' "$file" | tail -n +1 >> "$outfile" |
| 40 | |
| 41 | # Append TODO reminders |
| 42 | cat >> "$outfile" << EOF |
| 43 | |
| 44 | ## Triggers |
| 45 | <!-- TODO: Add 4-6 trigger phrases --> |
| 46 | |
| 47 | ## Don't |
| 48 | <!-- TODO: Add negative examples --> |
| 49 | EOF |
| 50 | |
| 51 | done |
| 52 | |
| 53 | echo "Done. Converted $(ls "$OUTPUT_DIR"/*.md 2>/dev/null | wc -l) files." |
| 54 | echo "Next: manually add triggers and examples to each file." |
Migration: SKILL.md to Cursor Rules
Going the other direction is simpler in some ways: Cursor rules don't require triggers or versioning, so you can strip those out. The key addition is glob patterns. Map your SKILL.md's scope instructions to Cursor-compatible globs.
| 1 | # SKILL.md scope instruction → Cursor glob mapping |
| 2 | "Apply when working with test files" → globs: ["**/*.test.ts", "**/*.spec.ts"] |
| 3 | "Apply when editing React components" → globs: ["src/**/*.tsx"] |
| 4 | "Apply when working with API routes" → globs: ["src/app/api/**/*.ts"] |
| 5 | "Always apply" → alwaysApply: true |
| 6 | "Apply when writing documentation" → globs: ["**/*.md", "docs/**"] |
Decision Matrix: When to Use Which
Use this table when you're deciding where to invest your rule-writing time. The answer depends on your workflow, team size, and how many tools you use.
| Scenario | Recommendation | Why |
|---|---|---|
| Solo dev, Cursor only | Cursor Rules | Glob activation is automatic - less friction |
| Solo dev, Claude Code only | SKILL.md | Native format, versioning built in |
| Solo dev, both tools | SKILL.md as source of truth | Easier to convert SKILL.md → MDC than reverse |
| Team, single tool | Tool's native format | Less cognitive overhead for the team |
| Team, multiple tools | SKILL.md + sync tool | One source, deploy to all tool directories |
| Heavy file-type rules | Cursor Rules | Glob patterns are more precise than trigger phrases |
| Heavy workflow automation | Claude Skills | Slash commands + triggers map better to workflows |
| Need versioning/audit | SKILL.md | Built-in version field, works with skill managers |
| Onboarding new devs | SKILL.md | Self-documenting format with examples and triggers |
Hybrid Approach: Best of Both Worlds
The most productive setup for developers using both tools is a hybrid: write your canonical skills as SKILL.md files in a central directory, then generate Cursor-specific MDC files from them. The SKILL.md is the source of truth. The MDC files are derived artifacts.
This works because SKILL.md is a superset of what Cursor rules contain. A SKILL.md has everything an MDC file needs (description, instructions, don'ts) plus extras (version, triggers, examples) that Cursor ignores but don't hurt. The only thing you need to add for the MDC version is the glob pattern.
| 1 | # Directory structure for hybrid approach |
| 2 | skills/ # Source of truth |
| 3 | ├── react-components.md |
| 4 | ├── testing-conventions.md |
| 5 | ├── api-design.md |
| 6 | ├── git-commits.md |
| 7 | └── glob-mappings.json # Maps skill → Cursor globs |
| 8 | |
| 9 | # glob-mappings.json |
| 10 | { |
| 11 | "react-components": ["src/**/*.tsx", "src/**/*.jsx"], |
| 12 | "testing-conventions": ["**/*.test.ts", "**/*.spec.ts"], |
| 13 | "api-design": ["src/app/api/**/*.ts"], |
| 14 | "git-commits": null // alwaysApply: true |
| 15 | } |
A sync script reads the SKILL.md files and the glob mappings, then generates MDC files for Cursor and copies the SKILL.md files to Claude's directory. You maintain one set of skills and both tools stay in sync.
Common Pitfalls When Migrating
Losing glob precision
When converting from Cursor to Claude, developers often forget to add scope instructions. The skill becomes universal when it should be scoped to specific file types. Always add a bold Scope line at the top of converted skills.
Fix: Add **Scope:** as the first line of the body, listing the file patterns this skill applies to.
Over-converting triggers
Cursor rules with alwaysApply don't need triggers in Claude - they're already always loaded. Adding triggers to an always-apply skill creates confusion about whether it's automatic or on-demand.
Fix: For always-apply rules, skip the Triggers section in SKILL.md. Just let it load as context.
Ignoring context window differences
A 3,000-word Cursor rule might work fine in Cursor's context but get truncated in Claude Code. Each tool has different context budgets for rules vs. skills.
Fix: Keep migrated skills under 1,500 words. Split large rules into focused sub-skills.
Format-specific syntax
Cursor rules sometimes use Cursor-specific syntax like @file references or @codebase. These don't work in Claude Code and need to be replaced with plain descriptions.
Fix: Replace @file references with explicit file path instructions. Replace @codebase with 'search the project for'.
Not testing after migration
Developers convert rules, drop them in the new directory, and assume they work. They don't test that the AI actually follows the instructions correctly in the new tool.
Fix: Test every converted skill 3-5 times in the target tool. Note where behavior diverges and adjust.
The Bigger Picture: Tool-Agnostic Skills
The industry is converging on Markdown-based skill files. Cursor MDC, Claude SKILL.md, Codex CLI skills, and Windsurf rules all use some flavor of Markdown with YAML headers. The differences are shrinking with every release. Writing your skills in clean, structured Markdown with YAML frontmatter gives you the most portable format - you can adapt it to any tool with minimal changes.
The real challenge isn't the format conversion - it's maintaining consistency across tools over time. A skill that's identical in Cursor and Claude today will diverge as you edit one copy and forget the other. This is the skill fragmentation problem, and it's why single-source-of-truth workflows (or tools like Praxl that manage the sync) matter more than any specific format choice.
Start with the tool you use most. Write great skills there. When you add a second tool, migrate systematically using the steps above rather than starting from scratch. Your investment in skill quality carries across tools - the format is just packaging.
Skip the manual conversion entirely
Everything in this guide assumes you're hand-converting Cursor rules to Claude skills (or vice-versa). If you want to skip that step, Praxl is a purpose-built skill manager that stores SKILL.md as the canonical format and automatically deploys to Cursor's rules directory, Claude Code's skills directory, and seven other AI tools simultaneously. Edit once, syncs everywhere — no migration step. There's a free tier (pricing) and the entire codebase is open source under AGPL-3.0, so you can self-host with all features unlocked. The security architecture uses two independent validation layers because writing into AI-tool directories is a real attack surface that deserves real defense.
Manage your skills with Praxl
Edit once, deployed to every AI tool. Version history, AI review, team sharing.
Try Praxl free
Praxl