Cursor cursor rules .cursorrules AI coding templates examples

Cursor Rules Examples and Templates: A Practical Guide for 2026

The Prompt Shelf ·

Without cursor rules, Cursor generates code that contradicts your project conventions on every other edit. With a good set of rules, it generates code that looks like it was written by a senior developer who has been on the project for months. The difference is real and measurable.

This guide covers the two rule formats Cursor currently supports, walks through seven copy-pasteable templates for the most common stacks, and ends with the mistakes that make even well-written rules fail.

Two Formats: .cursorrules vs .cursor/rules/*.mdc

Cursor has been transitioning from a single root-level .cursorrules file to a directory-based format under .cursor/rules/. Both work in 2026, but they behave differently and serve different purposes.

.cursorrules (legacy, still functional)

A single Markdown file at the root of your repository. Cursor reads it automatically for every chat and edit in the project. Simple to set up, universal coverage. The downside is that everything goes into one file, which gets unwieldy for large projects. There is also no way to scope rules to specific file types — frontend rules and backend rules live in the same document.

project-root/
└── .cursorrules

Modular rule files with frontmatter that control how and when each rule activates. Each file has a .mdc extension and lives in the .cursor/rules/ directory.

project-root/
└── .cursor/
    └── rules/
        ├── general.mdc
        ├── react-components.mdc
        ├── api-routes.mdc
        └── testing.mdc

The frontmatter supports two key fields:

---
description: "React component conventions for this project"
globs: ["src/components/**/*.tsx", "src/app/**/*.tsx"]
---

description — a short label. Cursor uses this when deciding which rules are relevant in “Agent Requested” mode.

globs — file patterns that trigger the rule automatically. When you open or edit a file matching the glob, the rule loads without you doing anything.

The four rule types

Cursor’s rule system has four activation modes:

TypeHow it activates
AlwaysLoads in every chat and Composer session
Auto (glob-based)Loads when you open a matching file
Agent RequestedAI decides when to load it based on the description
ManualOnly loads when you explicitly reference it

For most projects, a mix of Always (global conventions) and Auto (framework-specific rules) covers everything.

Which format to use

Start with .cursorrules if you want something working in five minutes. Migrate to .cursor/rules/ if your project has multiple distinct layers (frontend/backend/tests) that need different rules, or if the single file is getting unwieldy. The templates below use .cursorrules syntax so they work either way — drop them in a .cursorrules file or strip the frontmatter and use them as .mdc content.


Template 1: React / Next.js

The most common web stack. This covers App Router patterns, TypeScript conventions, and the component structure issues that trip up Cursor most often.

# Project Context

Next.js 15 application using App Router, TypeScript strict mode, Tailwind CSS, and Prisma with PostgreSQL.

## Tech Stack

- Next.js 15 with App Router (not Pages Router)
- TypeScript in strict mode. No `any`. Use `unknown` + type guards.
- Tailwind CSS for styling. Use `cn()` from `@/lib/utils` for conditional classes.
- Prisma ORM with PostgreSQL
- NextAuth.js v5 for authentication
- pnpm as package manager

## Component Rules

- Use arrow function components. No class components.
- Named exports only. No default exports except for page.tsx and layout.tsx.
- Mark client components with "use client" at the top. Default to Server Components.
- Do not fetch data in Client Components. Fetch in Server Components, pass as props.
- Props interface name: `ComponentNameProps`. Define it above the component.

## File and Folder Conventions

- Components: `src/components/` — kebab-case filenames, PascalCase component names
- Pages: `src/app/` — follow App Router conventions exactly
- Server actions: `src/actions/` — prefix with action (e.g., `createUser.ts`)
- Utilities: `src/lib/` — pure functions, no side effects
- Types: `src/types/` — shared TypeScript types and interfaces

## Import Order

1. React and Next.js
2. Third-party packages
3. Internal aliases (`@/components`, `@/lib`, etc.)
4. Relative imports
5. CSS/styles

Blank line between each group. Use `@/` aliases, not relative paths from `src/`.

## Code Style

- No semicolons (Prettier handles this)
- Single quotes for strings
- 2-space indentation
- Max line length: 100 characters
- No unused imports or variables — treat them as errors

## Database

- Never write raw SQL. Use Prisma Client only.
- All DB calls live in `src/lib/db/` functions, not in route handlers or Server Actions directly.
- Wrap mutations in try/catch. Return `{ data, error }` shape.

## Error Handling

- Use Next.js error.tsx for page-level errors
- API routes return `{ error: string }` with appropriate HTTP status codes
- Never expose internal error messages to the client

Template 2: Python (API / Backend)

Covers FastAPI projects but applies equally to Flask or Django projects with minor adjustments.

# Project Context

FastAPI backend service. Python 3.11+. Deployed on Railway with PostgreSQL (asyncpg) and Redis.

## Code Style

- Follow PEP 8 strictly
- Type hints on every function signature — parameters and return types
- Docstrings on public functions: one-line summary, then Args/Returns/Raises if non-trivial
- Maximum function length: 40 lines. Extract helpers if longer.
- No mutable default arguments

## Project Structure

- `app/routers/` — FastAPI router files, one per domain (users, auth, items)
- `app/services/` — business logic. No DB calls here, only service-level orchestration.
- `app/repositories/` — all DB queries. Returns domain models, not raw DB rows.
- `app/models/` — Pydantic models and SQLAlchemy models in separate files
- `app/core/` — config, dependencies, middleware

## FastAPI Conventions

- Use `Annotated` for dependency injection, not `Depends()` directly in function signature
- Router prefix and tags defined in the router file, not in main.py
- Response models on every endpoint. Never return raw dicts.
- Use async/await throughout. No synchronous DB calls.

## Database

- Use SQLAlchemy 2.0 style (not legacy Query API)
- All queries in repository layer. Service layer calls repositories.
- Migrations with Alembic. Never modify the DB schema outside of migrations.
- Connection pool: asyncpg. Handle `asyncpg.TooManyConnectionsError` in all DB functions.

## Error Handling

- Raise `HTTPException` with explicit `status_code` and `detail`
- Custom exception classes in `app/exceptions.py` for domain errors
- Global exception handler in `main.py` for unhandled exceptions

## Testing

- pytest with pytest-asyncio for async tests
- One test file per router file, in `tests/routers/`
- Use `httpx.AsyncClient` for endpoint tests
- Mock external services. Never hit real external APIs in tests.
- Minimum coverage: 80% on `app/services/` and `app/repositories/`

Template 3: Go (CLI or Service)

Go has strong conventions and Cursor knows them, but it helps to be explicit about the patterns you are actually using.

# Project Context

Go 1.22 service exposing a REST API. Uses chi router, sqlc for DB queries, and pgx/v5 with PostgreSQL.

## Code Style

- Follow effective Go and the Google Go Style Guide
- Error handling: check errors immediately, wrap with `fmt.Errorf("context: %w", err)`
- No panics in production code paths. Panics only in init() or package-level setup.
- Avoid named return values except when they clarify complex functions
- Receiver names: one or two letter abbreviation of the type (e.g., `u` for `User`)

## Project Structure

cmd/server/ — main.go only. Wire dependencies and start server. internal/ handler/ — HTTP handlers. Call service layer, handle request/response. service/ — business logic. No DB or HTTP concerns. repository/ — DB queries (sqlc-generated + hand-written for complex queries) domain/ — domain types and interfaces pkg/ — utilities safe to import externally


## Error Handling

- Define sentinel errors in the package they belong to
- Use `errors.Is` and `errors.As` for comparison, never string matching
- Handlers translate service errors to HTTP status codes — no business logic in handlers

## Interfaces

- Define interfaces at the point of use (in the consumer package), not the provider
- Keep interfaces small. One or two methods is ideal.
- Accept interfaces, return structs

## Database

- All queries via sqlc-generated code. Hand-write only when sqlc cannot express the query.
- Use pgx/v5 directly. No ORM.
- Transactions: pass `pgx.Tx` as first argument to repository methods that need them

## Testing

- Table-driven tests for pure functions
- Use `testify/require` for test assertions
- Integration tests in `_test.go` files with `//go:build integration` build tag
- Mock interfaces with `mockery` generated mocks

Template 4: TypeScript (Node.js Backend)

Node.js backends with TypeScript have their own patterns distinct from frontend TypeScript. This template is tuned for Express or Hono-based APIs.

# Project Context

Node.js REST API with TypeScript, Hono, Zod for validation, Drizzle ORM, and PostgreSQL. Runs on Bun.

## TypeScript Config

- `strict: true` in tsconfig.json
- No `any`. Use `unknown` for truly unknown data and narrow explicitly.
- `noUncheckedIndexedAccess: true` — always check array access results
- Prefer `type` over `interface` for this project (team preference)

## Project Structure

src/ routes/ — Hono route files, one per domain services/ — business logic db/ schema.ts — Drizzle schema definitions queries/ — query functions, one file per table middleware/ — auth, logging, error handler lib/ — shared utilities types/ — shared TypeScript types


## Validation

- All request bodies and params validated with Zod schemas
- Define schemas in a `schema.ts` file colocated with the route file
- Never trust input that has not passed a Zod parse

## Error Handling

- Custom `AppError` class extending `Error` with `statusCode` and `code` fields
- Central error handler middleware catches all `AppError` instances
- Return `{ error: { code: string, message: string } }` shape for all errors
- Use `Result<T, E>` pattern in service layer. Only throw in exceptional circumstances.

## Database

- All queries in `src/db/queries/` — no raw SQL in services or routes
- Use prepared statements for all parameterized queries
- Never return raw DB rows. Map to domain types in the query layer.

## Async

- `async/await` everywhere. No callback style.
- Handle promise rejections explicitly. No floating promises.
- Use `Promise.all()` for concurrent independent operations

Template 5: Python Data Science / ML

Data science projects have different conventions from production Python. This template handles notebooks, scripts, and ML pipelines.

# Project Context

Machine learning project in Python 3.11. Uses PyTorch, pandas, scikit-learn, and MLflow for experiment tracking. Development in Jupyter notebooks, production code in src/.

## Code Style

- Type hints on all src/ functions. Notebooks are more lenient.
- Black formatting with 88-char line length
- isort for import ordering
- Prefer explicit over implicit. Long variable names for clarity, not cleverness.

## Project Structure

data/ raw/ — original data, never modified processed/ — cleaned, transformed data features/ — feature-engineered datasets notebooks/ — exploration and prototyping src/ data/ — data loading and preprocessing modules features/ — feature engineering pipelines models/ — model definitions and training scripts evaluation/ — metrics and evaluation utilities mlruns/ — MLflow experiment tracking (auto-generated)


## Data Handling

- Raw data is read-only. Never modify files under data/raw/
- All data transformations return new DataFrames — no in-place modifications unless memory is a documented constraint
- Document shape assumptions: `# expects (N, 4) — [timestamp, open, high, close]`
- Validate DataFrame shapes and dtypes at function entry for any public-facing function

## Reproducibility

- Set random seeds at the top of every training script: `torch.manual_seed(42)`, `np.random.seed(42)`
- Log all hyperparameters to MLflow, not just the final metrics
- Pin exact package versions in requirements.txt (not `>=`)

## Model Code

- Separate model definition from training loop
- Training loop logs to MLflow: parameters, metrics per epoch, final artifact
- Save model checkpoints to MLflow artifacts, not to arbitrary local paths
- Evaluation functions return plain dicts of metric names to values — no side effects

## Testing

- pytest for src/ utilities and preprocessing functions
- At minimum, test that pipelines run without error on a small synthetic dataset
- No network calls in tests. Mock any external data sources.

Template 6: React Native / Expo

Mobile-specific patterns that Cursor often gets wrong without explicit rules.

# Project Context

React Native app using Expo SDK 52, TypeScript, and Expo Router for navigation. Target platforms: iOS and Android.

## Component Rules

- Use React Native primitives (View, Text, Pressable) — not div/button/p
- StyleSheet.create() for all styles. No inline style objects.
- No `style={{ marginTop: 10 }}` — define styles in the StyleSheet.
- PressableHitSlop minimum: `{ top: 10, bottom: 10, left: 10, right: 10 }` for small tap targets

## Navigation (Expo Router)

- File-based routing in app/ directory — follow Expo Router conventions exactly
- Typed routes: use `href` from `expo-router` with typed route parameters
- Stack, Tabs, and Modal layouts defined in _layout.tsx files
- Navigate with `router.push()` / `router.replace()` — not `navigation.navigate()`

## Platform-Specific Code

- Use Platform.select() or Platform.OS checks for platform differences
- Platform-specific files: `Component.ios.tsx` / `Component.android.tsx` when differences are significant
- Always test keyboard avoidance behavior on both platforms — use `KeyboardAvoidingView` with `behavior={Platform.OS === 'ios' ? 'padding' : 'height'}`

## State Management

- Zustand for global state. Jotai for derived/atomic state.
- React Query for server state. No custom fetch logic in components.
- AsyncStorage for persistence — accessed only through store actions, not directly in components

## Performance

- `useMemo` and `useCallback` for expensive computations and callbacks passed to list items
- FlashList instead of FlatList for lists longer than 20 items
- Avoid inline functions in render — especially as props to list items
- `React.memo()` on list item components

## Testing

- Jest + React Native Testing Library
- Use `fireEvent.press()` not `fireEvent.click()`
- Mock `expo-router` in tests that involve navigation

Template 7: Monorepo (Turborepo / pnpm Workspaces)

Monorepos need rules that clarify boundaries between packages and prevent cross-contamination.

# Project Context

Turborepo monorepo with pnpm workspaces. Contains a Next.js web app, a React Native mobile app, a shared UI component library, and a shared utilities package.

## Package Structure

apps/ web/ — Next.js 15 app (see apps/web/CURSOR.md for app-specific rules) mobile/ — Expo React Native app packages/ ui/ — shared React component library (runs on both web and mobile) utils/ — shared TypeScript utilities (no React, no platform-specific code) config/ — shared ESLint, TypeScript, and Tailwind configs


## Package Boundaries

- `packages/utils` must have zero React dependencies — pure TypeScript only
- `packages/ui` components must work in both web and mobile contexts
- Apps can import from packages. Packages must NEVER import from apps.
- No circular dependencies between packages.

## Shared UI Components

- Components in packages/ui export from a single index.ts
- Each component has a web variant and a mobile variant when platform behavior differs
- Exports: `ComponentName` (platform-agnostic), `ComponentNameWeb`, `ComponentNameNative`
- Use `react-native-web` primitives to maximize code sharing

## Turborepo Pipeline

- Do not add new scripts to turbo.json without updating all affected package.json files
- `build` depends on upstream `build`. `dev` does not.
- Cache keys: include relevant env variables in turbo.json env config

## TypeScript

- Each package has its own tsconfig.json extending `@repo/config/tsconfig/base.json`
- `paths` aliases are configured per-package — do not assume web aliases work in other packages
- Run `tsc --build` from root to check all packages together before pushing

Best Practices

Keep each rule file under 200 lines

Cursor has context limits. A 400-line .cursorrules file gets truncated or diluted. Split it into focused modules using the .cursor/rules/ format. General conventions in one file. Framework specifics in another. Testing rules in a third.

Be prescriptive, not descriptive

Weak rule: “Use TypeScript properly.” Strong rule: “No any. Use unknown and narrow with type guards. noUncheckedIndexedAccess is enabled — always check array access results.”

The first tells Cursor something it already knows. The second tells it what your specific project requires.

Document the why for unusual decisions

If your project has a non-obvious convention, say why it exists. Cursor will follow it more reliably and is less likely to silently override it when it seems like an “improvement.”

# Database layer returns { data, error } tuples rather than throwing.
# Reason: consistent error handling across async and sync code paths,
# and avoids try/catch nesting in service layer.

Use globs for context-sensitive activation

In .cursor/rules/, use globs to load rules only when relevant. Testing rules should not pollute component generation. Database rules should not appear in frontend contexts.

---
description: "Vitest testing conventions"
globs: ["**/*.test.ts", "**/*.spec.ts", "src/test/**"]
---

Reference external files for large context

Rules files support @file references for progressive disclosure. If you have a complex data model, link to it instead of embedding it:

See @schema.prisma for the full database schema.
See @src/types/api.ts for all API response types.

This keeps the rules file focused while giving Cursor access to specifics when needed.


Common Mistakes

Rules that are too vague

“Write clean, maintainable code” is useless. Cursor already tries to do this. Rules need to encode your specific decisions — the ones Cursor cannot infer from the codebase alone.

Contradicting rules

If your rules say “no default exports” but your existing files all use default exports, Cursor will follow the existing code patterns and ignore the rule. Fix the codebase first, or add a note like “new files only — legacy files use default exports but do not add new ones.”

Missing stack version context

“Use Next.js App Router patterns” means nothing without a version number. App Router in Next.js 13 and 15 have meaningfully different patterns. Include versions.

One massive file for a large project

A single .cursorrules with rules for 12 different subsystems gives each subsystem less effective weight. Use the .cursor/rules/ format and split by domain.

Rules that ignore your actual file structure

Cursor cannot follow rules like “put service logic in the service layer” if your project has no service layer folder. Rules work best when they describe something that already exists structurally in the project.


Getting Started

If you are starting from scratch, pick the template closest to your stack and do three things:

  1. Fill in the actual tech stack section with your real versions
  2. Delete any sections that do not apply to your project
  3. Add two or three project-specific conventions that Cursor would not know from context alone

Run it for a few sessions and note where Cursor still gets things wrong. Those are the gaps your rules need to fill. Rules are living documents — the version you write on day one will not be the version that is useful on day 30.

For the .cursor/rules/ migration path, see our guide on moving from .cursorrules to the new format. If you are evaluating whether to use Cursor rules or CLAUDE.md, check out our comparison of the two formats.

Related Articles

Explore the collection

Browse all AI coding rules — CLAUDE.md, .cursorrules, AGENTS.md, and more.

Browse Rules