·17 min read

20 .cursorrules Examples You Can Use Today

20 copy-paste .cursorrules examples for React, Next.js, Python, Go, Rust, and more. Real rules from production codebases, organized by language and framework.

If you've read the complete guide to Cursor rules, you know the theory. Now let's get practical. Below are 20 real-world .cursorrules and .cursor/rules/ examples you can copy directly into your project today.

Each example is drawn from patterns used in production codebases. They're organized by language and framework so you can find what applies to your stack.


React + Next.js

1. Next.js App Router (TypeScript)

The most common setup in 2026 — Next.js 15 with the App Router, TypeScript strict mode, and Tailwind.

## Stack
- Framework: Next.js 15 (App Router only — never Pages Router)
- Language: TypeScript 5 with strict mode enabled
- Styling: Tailwind CSS v4
- State: Zustand for global, useState for local
- Data fetching: Server Components by default, SWR for client-side

## Components
- Use named exports for all components
- Place components in `src/components/` organized by feature
- Server Components are the default — only add "use client" when required
- Use `React.FC` type annotations with explicit prop interfaces

## File naming
- Components: PascalCase (`UserProfile.tsx`)
- Utilities: camelCase (`formatDate.ts`)
- API routes: kebab-case directories (`api/user-profile/route.ts`)

## Do NOT
- Do not use the Pages Router (`pages/` directory)
- Do not use CSS modules — Tailwind utility classes only
- Do not add "use client" unless the component uses browser APIs or React hooks
- Do not use default exports for components

2. React Component Patterns

Focused purely on how components should be structured and documented.

## Component structure
Every component file should follow this order:
1. Imports (external libs, then internal)
2. Type/interface definitions
3. Component function
4. Helper functions (if small and only used here)

## Props
- Always define an interface named `[ComponentName]Props`
- Use `children: React.ReactNode` for wrapper components
- Mark optional props with `?` and document defaults in JSDoc

## State management
- Colocate state as close to where it's used as possible
- Extract complex state logic into custom hooks in `src/hooks/`
- Never store derived state — compute it from source of truth

## Event handlers
- Name handlers `handle[Action]` (`handleSubmit`, `handleInputChange`)
- Wrap in `useCallback` only when passed to memoized children

## Example component skeleton:
```tsx
interface ButtonProps {
  label: string;
  onClick: () => void;
  variant?: "primary" | "secondary";
  disabled?: boolean;
}

export function Button({ label, onClick, variant = "primary", disabled = false }: ButtonProps) {
  return (
    <button
      onClick={onClick}
      disabled={disabled}
      className={`btn btn-${variant}`}
    >
      {label}
    </button>
  );
}

### 3. React Query + API Layer

For projects using TanStack Query with a REST API.

```markdown
## Data fetching
- Use TanStack Query (React Query v5) for all server state
- Never fetch directly in components — use custom query hooks
- Place query hooks in `src/hooks/queries/` named `use[Resource].ts`

## Query hook pattern
```ts
export function useUser(userId: string) {
  return useQuery({
    queryKey: ["users", userId],
    queryFn: () => api.users.get(userId),
    staleTime: 5 * 60 * 1000, // 5 minutes
  });
}

Mutations

  • Use useMutation for all write operations
  • Invalidate relevant queries on success
  • Handle errors with toast notifications via Sonner

API client

  • All API calls go through src/lib/api.ts
  • Never use fetch directly in components or hooks
  • Type all request/response shapes with Zod schemas

### 4. Tailwind CSS Design System

For teams with an established component library and design tokens.

```markdown
## Design tokens
Use only colors from our design system:
- Primary: `bg-primary`, `text-primary`
- Destructive: `bg-destructive`, `text-destructive`
- Muted: `text-muted-foreground`, `bg-muted`
- Never use arbitrary colors like `text-[#3b82f6]`

## Spacing
- Use 4-unit spacing scale: `p-4`, `m-8`, `gap-2`, etc.
- Avoid arbitrary values (`p-[13px]`) unless in edge-case layouts
- Sections: `py-16 px-4 md:px-8 lg:px-16`

## Typography
- Headings: `text-2xl font-bold tracking-tight`
- Body: `text-base text-muted-foreground leading-relaxed`
- Code: `font-mono text-sm`

## Responsive
- Always mobile-first
- Breakpoints: `sm:` (640), `md:` (768), `lg:` (1024), `xl:` (1280)
- Never use `max-w-` breakpoint modifiers

## Accessibility
- Always include `aria-label` on icon-only buttons
- Use semantic HTML: `<button>`, `<nav>`, `<main>`, `<section>`
- Minimum tap target: `min-h-11` (44px)

Python + Django / FastAPI

5. Django REST Framework API

For Django projects using DRF to build a REST API.

## Stack
- Python 3.12+
- Django 5.x + Django REST Framework
- Database: PostgreSQL with psycopg (v3)
- Auth: JWT via djangorestframework-simplejwt
- Testing: pytest-django

## Code style
- Follow PEP 8 strictly
- Line length: 100 characters
- Use type hints everywhere (Python 3.10+ union syntax: `int | None`)
- Docstrings: Google style

## Models
- Always define `__str__` and `class Meta`
- Use `created_at` / `updated_at` timestamps on every model
- Prefer `TextChoices` over raw string choices

## Serializers
- One serializer per view action when input/output differ
- Use `read_only_fields` for computed fields
- Validate at the serializer level, not the view level

## Views
- Use class-based views with DRF generics or ViewSets
- Permission classes: always explicit (never rely on defaults)
- All endpoints must handle exceptions and return structured errors

## Do NOT
- Do not put business logic in views — use service functions in `services.py`
- Do not use raw SQL unless absolutely necessary — use the ORM
- Do not store secrets in settings.py — use environment variables via python-decouple

6. FastAPI + SQLAlchemy

Modern async Python API with FastAPI.

## Stack
- Python 3.12+, FastAPI 0.115+
- SQLAlchemy 2.0 (async, ORM style)
- Alembic for migrations
- Pydantic v2 for validation
- pytest + httpx for tests

## Project structure

src/ api/routes/ # Route handlers (thin layer) schemas/ # Pydantic request/response models models/ # SQLAlchemy ORM models services/ # Business logic repositories/ # Database access layer core/ # Config, database, security


## Async everywhere
- Use `async def` for all route handlers
- Use async SQLAlchemy sessions (`AsyncSession`)
- Never block the event loop with sync I/O

## Error handling
- Raise `HTTPException` with structured detail dicts
- Use custom exception handlers registered at app level
- Log all 5xx errors with full traceback

## Response models
- Always specify `response_model` in route decorators
- Never return ORM objects directly — convert via Pydantic

7. Python CLI Tool

For building command-line tools with Click or Typer.

## Stack
- Python 3.11+
- Typer for CLI interface
- Rich for terminal output
- Pydantic for config validation

## Output standards
- Use Rich Console for all output — never plain print()
- Errors: `console.print("[red]Error:[/red] message")`
- Success: `console.print("[green]✓[/green] Done")`
- Info: `console.print("[dim]Processing...[/dim]")`

## Commands
- Each command is a separate function with a Typer decorator
- Use `typer.Argument` for positional, `typer.Option` for flags
- Always include `--help` descriptions on every argument

## Config
- Load from `~/.config/[tool]/config.toml`
- Validate with Pydantic models
- Allow environment variable overrides prefixed with `TOOL_`

Go

8. Go REST API (Standard Library)

For Go services using the standard net/http package.

## Stack
- Go 1.23+
- Standard library `net/http` (not Gin or Echo)
- `database/sql` with `pgx` driver
- `encoding/json` for marshaling
- `slog` for structured logging

## Project structure (flat, idiomatic)

cmd/server/main.go internal/ handlers/ # HTTP handlers service/ # Business logic repository/ # Database layer domain/ # Types and interfaces


## Error handling
- Always return errors — never panic in production code
- Wrap errors with context: `fmt.Errorf("getting user: %w", err)`
- Define sentinel errors for expected failure modes

## HTTP handlers
- Handlers receive `(w http.ResponseWriter, r *http.Request)`
- Decode JSON input with explicit struct types
- Always call `json.NewEncoder(w).Encode` for responses
- Set `Content-Type: application/json` header explicitly

## Testing
- Table-driven tests for all business logic
- Integration tests with a real test database (testcontainers)
- `_test` package suffix for black-box testing

## Do NOT
- Do not use `interface{}` — use generics or concrete types
- Do not ignore errors — handle or explicitly discard with `_`
- Do not use `init()` functions

9. Go gRPC Service

For microservices using gRPC and protobuf.

## Stack
- Go 1.23+, gRPC, Protocol Buffers v3
- `connectrpc` for HTTP/gRPC compatibility
- `buf` for proto linting and generation

## Proto conventions
- One service definition per `.proto` file
- Use `google.protobuf.Timestamp` for time fields
- Version packages: `package myservice.v1;`

## Service implementation
- Implement generated server interface exactly
- Return `status.Errorf` with appropriate gRPC codes
- Never return raw Go errors — always wrap in gRPC status

## Interceptors
- Auth interceptor validates JWT on every non-public RPC
- Logging interceptor: method, duration, error code
- Recovery interceptor catches panics in handlers

## Testing
- Unit test each handler with mock dependencies
- Contract tests against real gRPC server with bufconn

TypeScript (Node.js / Bun)

10. TypeScript Node.js API (Express)

For Express APIs written in TypeScript.

## Stack
- Node.js 22+ or Bun 1.2+
- Express 5 with TypeScript
- Zod for input validation
- Drizzle ORM with PostgreSQL
- Vitest for testing

## Request validation
- Validate all request bodies with Zod schemas
- Infer TypeScript types from Zod schemas (`z.infer<typeof schema>`)
- Return 400 with field-level errors on validation failure

## Middleware order
1. CORS
2. Body parser (`express.json()`)
3. Request ID
4. Auth (JWT verification)
5. Rate limiting
6. Routes

## Error handling
- Use a centralized error handler middleware (last `app.use`)
- Custom `AppError` class with `statusCode` and `message`
- Never expose stack traces in production responses

## Environment config
- Use `zod` to parse and validate `process.env` at startup
- Fail fast on missing required env vars
- Export typed `config` object — never access `process.env` directly in app code

11. TypeScript Monorepo (Turborepo)

For large TypeScript monorepos with shared packages.

## Structure

apps/ web/ # Next.js frontend api/ # Backend API packages/ ui/ # Shared component library types/ # Shared TypeScript types utils/ # Shared utilities config/ # Shared ESLint, TS configs


## Import rules
- Apps can import from packages — never the reverse
- Packages can import from other packages (no circular deps)
- Always use the package name (`@company/ui`), not relative paths across packages

## Type sharing
- All shared types live in `packages/types`
- No `any` types — use `unknown` and narrow properly
- Prefer `interface` for public APIs, `type` for internal unions

## Build order
- Turborepo handles it — define `dependsOn` in `turbo.json`
- Each package has `build`, `dev`, `lint`, `test` scripts

## When adding a new package
- Create `packages/[name]/package.json` with proper exports
- Add to root `pnpm-workspace.yaml`
- Configure in `turbo.json` pipeline

12. Bun + Hono API

For fast, lightweight TypeScript APIs with Bun and Hono.

## Stack
- Bun 1.2+
- Hono v4 (TypeScript-first web framework)
- Zod for validation
- Drizzle ORM

## Route structure
```ts
const app = new Hono()

app.get("/users/:id", async (c) => {
  const id = c.req.param("id")
  const user = await db.query.users.findFirst({ where: eq(users.id, id) })
  if (!user) return c.json({ error: "Not found" }, 404)
  return c.json(user)
})

Middleware

  • Use hono/jwt for auth middleware
  • Use hono/logger for request logging
  • Use hono/cors for CORS — always configure origins explicitly

Testing

  • Bun's built-in test runner (bun test)
  • Use Hono's app.request() for route-level tests — no server needed

---

## Rust

### 13. Rust Web Service (Axum)

For Rust web APIs using the Axum framework.

```markdown
## Stack
- Rust (stable, latest)
- Axum 0.8 for HTTP
- SQLx with PostgreSQL (compile-time checked queries)
- Serde for JSON serialization
- Tokio async runtime

## Error handling
- Define a central `AppError` type that implements `IntoResponse`
- Use `thiserror` for error derivation
- Return `Result<impl IntoResponse, AppError>` from all handlers
- Never `unwrap()` in production code paths — use `?` or explicit handling

## State
- Pass shared state via Axum's `State` extractor
- State struct contains: `db_pool`, `config`, `http_client`
- Clone is cheap — use `Arc` inside State for owned data

## Async
- `async`/`await` throughout
- Spawn blocking operations with `tokio::task::spawn_blocking`
- Use `tokio::time::timeout` for all external calls

## Serialization
- Derive `Serialize`, `Deserialize` on all API types
- Use `#[serde(rename_all = "camelCase")]` on response types
- Use `Option<T>` for nullable fields, not empty strings

14. Rust CLI Tool

For building system tools and CLIs in Rust.

## Stack
- Rust (stable)
- clap v4 with derive macros
- indicatif for progress bars
- colored for terminal output
- anyhow for error handling

## CLI structure
```rust
#[derive(Parser)]
#[command(name = "mytool", about = "...")]
struct Cli {
  #[command(subcommand)]
  command: Commands,
}

#[derive(Subcommand)]
enum Commands {
  Build { path: PathBuf },
  Deploy { #[arg(long)] env: String },
}

Error handling

  • Use anyhow::Result in main() and top-level functions
  • Use thiserror for library-facing error types
  • Provide user-friendly messages — never expose internal error chains directly

Output

  • Respect --quiet and --verbose flags
  • Write errors to stderr (eprintln!), output to stdout
  • Use indicatif for long-running operations

---

## Infrastructure + DevOps

### 15. Terraform + AWS

For teams managing AWS infrastructure with Terraform.

```markdown
## Style
- Use HCL format with 2-space indent
- Group resources logically with blank lines and comments
- Name resources: `[environment]_[service]_[type]` (e.g., `prod_api_security_group`)

## Modules
- Extract repeating patterns into modules in `modules/`
- Use module outputs to share values — never hardcode ARNs
- Pin module versions: `source = "./modules/rds"` with explicit version tags

## Variables
- Define all variables in `variables.tf` with type constraints and descriptions
- Mark sensitive variables with `sensitive = true`
- Use `locals.tf` for computed values, not inline expressions

## State
- Remote state in S3 with DynamoDB locking
- One workspace per environment (dev, staging, prod)
- Never run `terraform apply` without reviewing `terraform plan` output

## Do NOT
- Do not hardcode account IDs or region names — use data sources
- Do not commit `.tfstate` files
- Do not use `count` for resources that differ significantly — use `for_each`

16. Docker + CI/CD

For projects with Docker builds and GitHub Actions pipelines.

## Dockerfile
- Use official base images pinned to digest (`node:22-alpine@sha256:...`)
- Multi-stage builds: builder stage + minimal runtime stage
- Run as non-root user in production images
- `COPY` only necessary files — keep images lean

## Docker Compose
- `docker-compose.yml` for local dev only
- `docker-compose.override.yml` for developer-specific overrides (gitignored)
- Services: app, postgres, redis — match production topology

## GitHub Actions
- Reuse actions via composite actions in `.github/actions/`
- Pin action versions to commit SHA, not tags
- Secrets via `${{ secrets.NAME }}` — never hardcode
- Cache node_modules or build outputs via `actions/cache`

## CI pipeline order
1. Lint + type check
2. Unit tests
3. Integration tests
4. Build Docker image
5. Push to registry
6. Deploy to staging
7. Smoke test staging
8. Deploy to production (manual approval)

Database

17. Drizzle ORM + PostgreSQL

For TypeScript projects using Drizzle ORM.

## Schema
- Define all tables in `src/db/schema.ts`
- Use Drizzle's `pgTable` with typed column helpers
- Always define `createdAt` and `updatedAt` on every table
- Use `pgEnum` for columns with a fixed set of values

## Queries
- Use prepared statements for frequently run queries
- Use `db.transaction()` for multi-step writes
- Prefer `db.query` (relational API) over `db.select` for joined data
- Always destructure the result — never leave raw query objects in business logic

## Migrations
- Generate via `drizzle-kit generate`
- Review generated SQL before applying
- Never edit generated migration files — regenerate instead
- Apply to production with zero-downtime techniques (add before drop)

## Types
- Infer TypeScript types from schema: `type User = typeof users.$inferSelect`
- Separate insert types: `type NewUser = typeof users.$inferInsert`
- Never write manual type definitions that duplicate schema types

18. Prisma ORM

For TypeScript projects using Prisma.

## Schema conventions
- camelCase field names, PascalCase model names
- Always include `id`, `createdAt`, `updatedAt` on every model
- Use `@relation` explicitly — don't rely on implicit naming
- Enums for status fields: `enum Status { ACTIVE INACTIVE PENDING }`

## Queries
- Use Prisma Client extensions for reusable query modifiers
- Prefer `findFirst` over `findUnique` when you don't need the uniqueness guarantee
- Always `select` specific fields in list queries — never return entire records
- Use `include` for relations only when needed in the response

## Performance
- Batch reads with `findMany` + `where: { id: { in: ids } }`
- Avoid N+1: use `include` or batch queries, not loops
- Add `@@index` on foreign keys and frequently queried fields

## Migrations
- Use `prisma migrate dev` locally — never edit migration files
- Shadow database for migration safety in CI
- `prisma migrate deploy` in production (not `dev`)

Testing

19. Vitest + Testing Library

For React projects with Vitest and Testing Library.

## Testing philosophy
- Test behavior, not implementation
- Don't test internal state — test what the user sees
- One assertion per test when possible — split large tests

## File structure
- Co-locate tests: `Button.tsx``Button.test.tsx`
- Integration tests: `src/tests/`
- Test utilities and custom renders: `src/tests/utils.tsx`

## Queries (preference order)
1. `getByRole` (most accessible)
2. `getByLabelText`
3. `getByText`
4. `getByTestId` (last resort only)

## Async
- Always use `findBy*` for async DOM updates (not `waitFor` + `getBy*`)
- Use `userEvent` from `@testing-library/user-event`, not `fireEvent`

## Mocking
- Mock at the module boundary: `vi.mock("../services/api")`
- Reset mocks in `beforeEach` — never share mock state between tests
- Use `msw` for API mocking in integration tests

## Do NOT
- Do not test implementation details (state variables, internal methods)
- Do not snapshot test large components — they become meaningless fast
- Do not mock the module under test

20. Playwright E2E

For end-to-end testing with Playwright.

## Structure

tests/e2e/ auth.spec.ts # Login, logout, session checkout.spec.ts # Purchase flow fixtures/ auth.ts # Authenticated page fixture pages/ LoginPage.ts # Page Object Model classes


## Page Object Model
- Encapsulate all selectors and actions in page classes
- Never use raw selectors (`page.click(".btn-submit")`) in spec files
- Methods return `Promise<void>` or meaningful values — not `Page`

## Selectors (preference order)
1. `getByRole` — matches accessible roles
2. `getByLabel` — for form fields
3. `getByText` — visible text
4. `data-testid` — only for elements without accessible names

## Test isolation
- Each test starts with a fresh browser context
- Use `storageState` to restore authenticated sessions (fast)
- Never depend on test execution order

## CI
- Run in headless mode
- Capture video and screenshots on failure (`video: "retain-on-failure"`)
- Shard tests across workers for speed

Sharing and Reusing These Rules

Writing good rules takes work. The frustrating part is that once you've tuned a set of Cursor rules for your Next.js project, you can't easily reuse them across your other repos — let alone share them with teammates.

This is exactly the problem localskills.sh solves. You publish your rules once, and install them anywhere with a single command:

localskills install your-team/nextjs-conventions --target cursor

Rules are written into .cursor/rules/ and tracked by the CLI. When you update the published skill, teammates pull the latest version with localskills pull.

Because a single published skill can install into multiple AI tools at once, you stop maintaining the same rules in three different formats. One source of truth, everywhere:

localskills install your-team/api-conventions --target cursor claude windsurf

If you're building out your first set of rules and want to understand how to organize them well, the complete guide to Cursor rules covers the .cursorrules vs .cursor/rules/ folder decision in depth. And once you've got something worth sharing, publishing your first skill takes about five minutes.


Ready to install and share rules across your team? Get started in minutes.

npm install -g @localskills/cli
localskills login
localskills publish

Create your free account at localskills.sh/signup and start sharing rules that make your entire team's AI coding more consistent.