Cursor .cursorrules File: Project-Specific AI Instructions Guide

Write a .cursorrules file that gives Cursor exactly the right context for your project. Fewer wrong suggestions, faster coding, better output.

Problem: Cursor Ignores Your Project's Rules Without a .cursorrules File

You ask Cursor to add a feature and it generates code in a style your team banned six months ago. It imports a library you replaced. It writes a React component with class syntax when your whole codebase uses hooks. You fix it, re-prompt, and it happens again in the next file.

The fix is a .cursorrules file — a plain text file at your project root that tells Cursor's AI exactly how your project works.

You'll learn:

  • What .cursorrules does and how Cursor reads it
  • How to structure rules that actually change AI behavior
  • Ready-to-use templates for Next.js, FastAPI, and monorepos
  • What to put in rules vs what to leave out

Time: 20 min | Difficulty: Intermediate


Why Cursor Gives Generic Output Without Rules

Cursor's AI has no memory of your previous sessions. Every tab, every file — it starts cold. Without a .cursorrules file, it falls back to broad training defaults: common patterns, popular libraries, the "average" React project.

Your project isn't average. It has specific conventions, banned patterns, and architectural decisions that took months to settle.

.cursorrules is Cursor's equivalent of onboarding documentation for the AI. It gets injected into the system prompt for every request in that project.

What it affects:

  • Composer and Agent mode (full file generation)
  • Inline completions (Tab suggestions)
  • Chat responses in the context of your codebase
  • @codebase queries

Solution

Step 1: Create the File at Project Root

# From your project root
touch .cursorrules

The file must be named exactly .cursorrules (dot prefix, no extension). Cursor detects it automatically when you open the project folder. No configuration needed.


Step 2: Write the Project Identity Block

Start every .cursorrules file with a brief project identity section. This is the highest-signal context you can give the AI.

# Project: Acme Dashboard
# Stack: Next.js 15, TypeScript 5.4, Tailwind CSS 3.4, Drizzle ORM, PostgreSQL
# Runtime: Node 22, Bun for scripts
# State: Zustand (no Redux, no Context API for global state)
# Auth: Clerk (not NextAuth)
# Hosting: Vercel (edge runtime where possible)

Keep it to one line per decision. Don't explain the choices — just state them. The AI doesn't need the backstory; it needs the constraint.


Step 3: Add a Banned Patterns Section

This is the most valuable section. Be explicit about what not to do.

## Do Not Use
- `var` — always `const` or `let`
- `React.FC` type — use explicit return types instead
- Default exports from component files — named exports only
- `any` type — use `unknown` and narrow it
- `useEffect` for data fetching — use React Query or server components
- `console.log` in committed code — use the `logger` utility at `lib/logger.ts`
- Inline styles — Tailwind classes only
- `axios` — project uses native `fetch` with a wrapper at `lib/api.ts`

The AI will actively avoid these patterns when generating code. This alone cuts correction cycles in half for most teams.


Step 4: Define Naming and File Conventions

## File Conventions
- Components: `PascalCase.tsx` in `components/` subdirectory by feature
- Hooks: `use-kebab-case.ts` in `hooks/`
- Utilities: `kebab-case.ts` in `lib/`
- API routes: `app/api/[resource]/route.ts` (Next.js App Router pattern)
- Types: co-locate with the module that owns them; shared types in `types/`

## Naming
- Boolean variables: `isLoading`, `hasError`, `canEdit` (verb prefix)
- Event handlers: `handleClick`, `handleSubmit` (handle prefix)
- Async functions: descriptive verb, e.g., `fetchUserProfile`, `updateInvoice`
- Database queries: suffix with `Query`, e.g., `getUserQuery`, `listOrdersQuery`

Step 5: Specify Code Style Rules

## Code Style
- Prefer early returns over nested conditionals
- Extract logic > 15 lines into a named function
- One exported component per file
- Zod schemas defined next to the route or form that uses them
- Server Components by default; add `"use client"` only when needed
- All database access goes through `lib/db/` — never import Drizzle directly in components

These are the "style guide" rules that normally live in a document nobody reads. Putting them here means the AI reads them every time.


Step 6: Add a Testing Section (If Relevant)

## Testing
- Test framework: Vitest (not Jest)
- Component tests: React Testing Library, test behavior not implementation
- Mock location: `__mocks__/` at project root
- Test files: co-located with source, named `*.test.ts` or `*.spec.ts`
- Do not test internal state — test what the user sees

Step 7: Describe the Architecture for Agent Mode

When using Cursor Agent to build entire features, it needs to know where things live:

## Architecture
- `app/` — Next.js App Router pages and layouts
- `components/` — UI components (no business logic)
- `features/` — feature-specific components, hooks, and types
- `lib/` — utilities, API clients, DB access, third-party wrappers
- `server/` — server actions and server-only utilities
- `types/` — shared TypeScript types and Zod schemas

When adding a new feature:
1. Create `features/[feature-name]/` directory
2. Put the component, hook, and types inside it
3. Export from `features/[feature-name]/index.ts`
4. Add the server action to `server/actions/[feature-name].ts`

This is especially useful for Agent mode, which plans file structure before writing code.


Complete Templates

Next.js 15 App Router

# Project Stack
# Framework: Next.js 15 App Router
# Language: TypeScript 5.4 (strict mode)
# Styling: Tailwind CSS 3.4
# Database: PostgreSQL via Drizzle ORM
# Auth: Clerk
# State: Zustand for client state, React Query for server state
# Testing: Vitest + React Testing Library

## Do Not Use
- `React.FC` — explicit return types only
- Default exports from components — named exports only
- `useEffect` for data fetching — use React Query or server components
- `any` type — use `unknown` and narrow
- `axios` — use `lib/api.ts` fetch wrapper
- Redux or Context API for global state — use Zustand
- `console.log` — use `lib/logger.ts`

## File Conventions
- Components: `PascalCase.tsx` in `components/[feature]/`
- Hooks: `use-kebab-case.ts` in `hooks/`
- Server actions: `server/actions/[resource].ts`
- Utilities: `lib/[utility].ts`

## Code Style
- Server Components by default; `"use client"` only when required
- Prefer early returns over nested conditionals
- Co-locate Zod schemas with the route or form using them
- All DB access through `lib/db/` — not directly in components

## Architecture
- `app/` — pages and layouts
- `components/` — reusable UI (no business logic)
- `features/` — feature modules with their own components/hooks/types
- `lib/` — shared utilities and wrappers
- `server/` — server actions and server-only code
- `types/` — shared TypeScript types

FastAPI + Python Backend

# Project Stack
# Framework: FastAPI 0.115
# Python: 3.12
# Package manager: uv
# ORM: SQLModel (not SQLAlchemy directly)
# Validation: Pydantic v2
# Auth: JWT via python-jose
# Testing: pytest + httpx

## Do Not Use
- `print()` — use `structlog` logger
- Mutable default arguments in function signatures
- `Optional[X]` — use `X | None` (Python 3.10+ union syntax)
- Bare `except:` — always catch specific exceptions
- Direct `os.environ` access — use `settings` from `config.py`
- Synchronous DB calls in async routes — use `await` throughout

## File Conventions
- Routers: `routers/[resource].py`
- Models: `models/[resource].py` (SQLModel table models)
- Schemas: `schemas/[resource].py` (Pydantic request/response models)
- Services: `services/[resource].py` (business logic)
- Dependencies: `dependencies/[concern].py`

## Code Style
- One router per resource
- Services contain business logic — routers only call services
- Raise `HTTPException` only in routers — services raise domain exceptions
- All DB sessions injected via `Depends(get_session)`
- Response models always explicitly typed on route decorator

## Testing
- Test file mirrors source: `tests/routers/test_[resource].py`
- Use `httpx.AsyncClient` for route tests
- DB: use a test database, never mock the ORM

Monorepo (Turborepo + Next.js + Shared Packages)

# Project Stack
# Monorepo: Turborepo
# Apps: `apps/web` (Next.js 15), `apps/api` (Hono + Bun)
# Packages: `packages/ui`, `packages/db`, `packages/config`
# Language: TypeScript 5.4 across all packages
# Package manager: pnpm workspaces

## Do Not Use
- Cross-app direct imports — use shared packages only
- `any` type
- Hardcoded environment strings — use `packages/config` env validation
- Direct database imports in `apps/web` — use `packages/db`

## Import Rules
- UI components: import from `@acme/ui`
- Database access: import from `@acme/db`
- Shared types: import from `@acme/types`
- Never import from `apps/*` in packages

## When Adding a New Shared Component
1. Create in `packages/ui/src/[component-name].tsx`
2. Export from `packages/ui/src/index.ts`
3. Add to `packages/ui/package.json` exports if needed
4. Use in apps via `@acme/ui`

## Turborepo
- Tasks defined in `turbo.json` — don't add scripts that bypass Turbo pipeline
- Cache inputs declared per task — update when adding new env vars to builds

Verification

Open any file in your project and trigger Cursor with a prompt that would normally produce a banned pattern. For example, if you've banned axios, prompt:

Add a function to fetch user data from /api/users

You should see: Cursor use your lib/api.ts wrapper (or fetch) instead of importing axios.

To confirm Cursor is reading the file, open Cursor Chat and ask:

What are the banned patterns in this project?

It should list exactly what you wrote in the ## Do Not Use section.


What You Learned

  • .cursorrules injects context into every AI request in the project — it's not just for Composer
  • The banned patterns section has the highest ROI — it directly prevents the most common correction loops
  • Keep rules declarative and terse; the AI doesn't need explanations, just constraints
  • Architecture sections matter most for Agent mode, which plans before it writes

Limitation: .cursorrules is read per-project, not globally. If you have standards that apply across all projects, Cursor also supports user-level rules in Settings → Rules for AI — but project-level rules always take precedence for that project.

When rules don't seem to work: Rules that conflict with each other or are written as vague preferences ("prefer clean code") get ignored. Be specific and use negative instructions ("do not use X") — they outperform positive style guidance.

Tested on Cursor 0.45, macOS Sequoia 15.3 and Ubuntu 24.04