How to Set Up Cursor Rules Files for Project-Specific AI Code Generation
How to Set Up Cursor Rules Files for Project-Specific AI Code Generation
Cursor Rules files let you define project-specific instructions that shape how Cursor’s AI generates code. By configuring custom linting preferences, framework conventions, and team-shared prompt templates, you ensure every AI suggestion aligns with your codebase standards. This guide walks you through the complete setup process.
What Are Cursor Rules Files?
Cursor Rules are instruction files placed in your project that the AI reads before generating any code. They act as persistent context, telling the AI about your preferred coding style, framework patterns, forbidden practices, and team conventions. Unlike one-off prompts, rules apply automatically to every interaction within the project.
Cursor supports two rule systems: the legacy .cursorrules file (a single file in the project root) and the newer Project Rules system using the .cursor/rules/ directory, which supports multiple rule files with glob-based scoping.
Step-by-Step Setup
Step 1: Create the Rules Directory
Open your terminal in the project root and create the rules directory structure:
mkdir -p .cursor/rules
This directory will hold all your rule files. Each file uses the .mdc extension (Markdown with Context).
Step 2: Create a Global Project Rule
Create a file at .cursor/rules/global.mdc that applies to all files in your project:
---
description: Global coding standards for the entire project
globs: */
alwaysApply: true
Project Coding Standards
General Rules
- Use TypeScript strict mode for all
.ts and .tsx files
- Prefer named exports over default exports
- Use early returns to reduce nesting
- Maximum function length: 40 lines
- All public functions must have JSDoc comments
Naming Conventions
- Components: PascalCase (e.g.,
UserProfile)
- Hooks: camelCase with
use prefix (e.g., useAuthState)
- Utilities: camelCase (e.g.,
formatCurrency)
- Constants: UPPER_SNAKE_CASE (e.g.,
MAX_RETRY_COUNT)
- File names: kebab-case (e.g.,
user-profile.tsx)
Forbidden Patterns
- Never use
anytype — useunknownand narrow - Never use
var— useconstorlet - No console.log in production code — use the logger utility
No inline styles in React components
Step 3: Add Framework-Specific Rules
Create a rule scoped to your framework files. For a Next.js project, create .cursor/rules/nextjs.mdc:
---
description: Next.js App Router conventions
globs: src/app/**/*
alwaysApply: false
---
Next.js App Router Rules
- Use Server Components by default; add “use client” only when needed
- Data fetching happens in Server Components using async/await
- Use
loading.tsx for Suspense boundaries, error.tsx for error handling
- API routes go in
src/app/api/ using Route Handlers
- Use Next.js
Image component, never raw <img> tags
- Metadata must use the
generateMetadata function or static metadata export
Route Handler Pattern
import { NextRequest, NextResponse } from 'next/server';
export async function GET(request: NextRequest) {
// validate, process, respond
return NextResponse.json({ data });
}
```</code></pre>
### Step 4: Configure Custom Linting Rules
<p>Create <code>.cursor/rules/linting.mdc</code> to enforce linting conventions in AI output:
<code>---
description: Linting and formatting standards
globs: "**/*.{ts,tsx,js,jsx}"
alwaysApply: true
---
# Linting Rules for AI-Generated Code
- Follow the ESLint config in `.eslintrc.js` — do not generate code that violates it
- Use Prettier defaults: single quotes, no semicolons, 2-space indent
- Import order: (1) Node built-ins, (2) external packages, (3) internal aliases, (4) relative paths
- Unused imports must not appear in generated code
- Prefer `interface` over `type` for object shapes
- Use `satisfies` operator for type-safe object literals
## Example Correct Import Order
```typescript
import { readFile } from 'node:fs/promises';
import express from 'express';
import { z } from 'zod';
import { db } from '@/lib/database';
import { logger } from '@/lib/logger';
import { formatDate } from '../utils/date';
```</code></pre>
### Step 5: Create Team-Shared Prompt Templates
<p>Create <code>.cursor/rules/templates.mdc</code> for reusable patterns your team relies on:
<code>---
description: Team prompt templates and code patterns
globs: src/**/*
alwaysApply: false
---
# Team Code Templates
## API Service Pattern
When creating a new API service, follow this structure:
```typescript
import { apiClient } from '@/lib/api-client';
import type { ApiResponse } from '@/types/api';
export const userService = {
async getAll(params?: { page: number; limit: number }): Promise<ApiResponse<User[]>> {
return apiClient.get('/users', { params });
},
async getById(id: string): Promise<ApiResponse<User>> {
return apiClient.get(`/users/${id}`);
},
} as const;
React Component Pattern
When generating React components, use this structure:
interface ComponentNameProps {
// props here
}
export function ComponentName({ prop1, prop2 }: ComponentNameProps) {
// hooks first
// derived state
// handlers
// early returns for loading/error
// main render
}
Zod Validation Pattern
Always validate external input with Zod:
import { z } from 'zod';
const createUserSchema = z.object({
email: z.string().email(),
name: z.string().min(2).max(100),
role: z.enum(['admin', 'user', 'viewer']),
});
type CreateUserInput = z.infer<typeof createUserSchema>;
```</code></pre>
### Step 6: Commit and Share with Your Team
<p>Add the rules directory to version control so every team member benefits:
<code>git add .cursor/rules/
git commit -m "Add Cursor rules for consistent AI code generation"
git push origin main</code></pre><p>Team members will automatically pick up the rules when they pull the latest changes and use Cursor in the project.
## Rule File Configuration Reference
<table><thead><tr><th>Frontmatter Field</th><th>Type</th><th>Purpose</th></tr></thead><tbody><tr><td><code>description</code></td><td>String</td><td>Tells the AI when this rule is relevant</td></tr><tr><td><code>globs</code></td><td>String or Array</td><td>File patterns this rule applies to (e.g., <code>src/**/*.tsx</code>)</td></tr><tr><td><code>alwaysApply</code></td><td>Boolean</td><td>If <code>true</code>, the rule loads for every AI request</td></tr></tbody></table>
## Pro Tips
- **Layer your rules:** Use <code>alwaysApply: true</code> for universal standards and <code>alwaysApply: false</code> with specific globs for context-sensitive rules. The AI picks the right rules based on which files you're editing.- **Include anti-patterns:** Showing the AI what NOT to do is as valuable as showing what to do. Add a "Forbidden Patterns" section with concrete examples of bad code and the correct alternative.- **Reference your config files:** Use <code>@eslintrc.js</code> or <code>@tsconfig.json</code> syntax inside rule files to tell Cursor to read those files for additional context.- **Keep rules concise:** Overly long rule files dilute the AI's focus. Aim for 50–150 lines per rule file. Split large rule sets into multiple scoped files.- **Test iteratively:** After adding a rule, generate code in the affected scope and verify the AI follows it. Refine wording if the AI misinterprets instructions.
## Troubleshooting
<table><thead><tr><th>Problem</th><th>Cause</th><th>Solution</th></tr></thead><tbody><tr><td>Rules not being applied</td><td>File not in <code>.cursor/rules/</code> or missing <code>.mdc</code> extension</td><td>Verify path is <code>.cursor/rules/filename.mdc</code> and restart Cursor</td></tr><tr><td>Rules applied to wrong files</td><td>Incorrect glob pattern</td><td>Test globs at [globster.xyz](https://globster.xyz) and update the <code>globs</code> field</td></tr><tr><td>AI ignores specific instructions</td><td>Rule is too vague or conflicts with another rule</td><td>Make instructions explicit with code examples; check for contradictions across rule files</td></tr><tr><td>Legacy <code>.cursorrules</code> conflicts</td><td>Both old and new systems present</td><td>Migrate content from <code>.cursorrules</code> to <code>.cursor/rules/</code> and delete the legacy file</td></tr><tr><td>Rules too long, AI loses focus</td><td>Single rule file exceeds practical context</td><td>Split into multiple files with narrow globs, each under 150 lines</td></tr></tbody></table><!-- RELATED_CONTENT_PLACEHOLDER -->
## Frequently Asked Questions
### Can I use both .cursorrules and the .cursor/rules/ directory at the same time?
Technically both can coexist, but it is not recommended. The newer <code>.cursor/rules/</code> system is more powerful because it supports multiple files with glob-based scoping and frontmatter configuration. Migrate your legacy <code>.cursorrules</code> content into scoped <code>.mdc</code> files in the rules directory for better control and maintainability.
### Do Cursor Rules affect AI responses in Chat, Composer, and Tab completion equally?
Yes. Rules with <code>alwaysApply: true</code> are injected into every AI interaction regardless of the interface. Rules with <code>alwaysApply: false</code> are included only when the active file matches the glob pattern. This applies consistently across Chat, Composer (Cmd+I / Ctrl+I), and inline Tab completions.
### How do I organize rules for a monorepo with multiple frameworks?
Create separate rule files scoped to each package or app directory. For example, use <code>globs: packages/frontend/**/*</code> for React rules and <code>globs: packages/api/**/*</code> for backend rules. Shared conventions can go in a global rule with <code>globs: **/*</code>. This ensures each part of the monorepo gets only the relevant instructions without cross-contamination.