Every time you open a new AI coding session without project memory files, you pay a tax. You explain the stack. You correct the wrong import pattern. You remind it that you're using Prisma, not Sequelize. You fix the test it wrote for Jest when your project uses Vitest. You do this every single session, hundreds of times a year, for every project you work on.
.cursorrules and CLAUDE.md eliminate that tax. They're configuration files that load automatically into your AI's context — before you type a single word. The AI walks into your codebase already knowing what it needs to know.
What each file does
.cursorrules is Cursor's project-level instruction file. Drop it in the root of your repository and every prompt in that project automatically includes its contents. It runs silently in the background — you don't reference it explicitly, it just shapes every response.
CLAUDE.md is Claude Code's equivalent. When you run Claude Code in a directory containing a CLAUDE.md, it reads the file at session start and treats its contents as project context. It also recognizes CLAUDE.md files in subdirectories for monorepos where different services have different conventions.
They do functionally the same thing: persistent, project-scoped instructions that travel with the code. The syntax differs slightly and each tool picks up its own file — but the concept and content are nearly identical.
What to put in a .cursorrules file
Think of it as the onboarding doc you'd give a new senior engineer on their first day. Not a tutorial — a reference. The things they'd need to know to write code that looks like it belongs.
Stack and versions (be specific)
Stack:
- Next.js 15 (App Router — no Pages Router anywhere in this project)
- TypeScript 5.4 with strict mode enabled
- Prisma 5.x with PostgreSQL
- Tailwind CSS v4 (plugins declared in globals.css with @plugin, NOT tailwind.config)
- shadcn/ui components in src/components/ui/
- Zod for all schema validation
- next-auth v5 for authentication
Vague stack declarations ("we use React") are useless. Version specificity prevents the AI from using deprecated APIs.
Architectural patterns
Architecture:
- Service layer pattern: all database calls live in src/services/*.ts, never directly in route handlers or components
- Repository pattern: Prisma queries wrapped in repository functions, not called directly
- Server Actions for form submissions (no API routes for forms)
- API routes for external-facing endpoints only (/api/*)
- Zod schema validation at every API boundary — define schemas in src/schemas/
Without this, the AI will create database queries inline in components, mix server and client code in unexpected ways, and route form submissions through the wrong pattern for your project.
Code style rules
Code style:
- Named exports only — no default exports anywhere (ESLint rule enforces this)
- Import order: external packages → internal absolute imports (~/...) → relative imports
- Use ~/components, ~/lib, ~/services as absolute import aliases (configured in tsconfig)
- Async/await throughout — no .then() chains
- Error handling: always use our custom AppError class from ~/lib/errors, not new Error()
- Logging: use our logger from ~/lib/logger, not console.log
The import order rule alone saves a dozen AI-generated linting errors per session.
What NOT to do
This section might be the most valuable. Every time you find yourself correcting the AI for the same mistake twice, add a rule here.
Never do these:
- Never use setTimeout for delays — use our delay() utility from ~/lib/utils
- Never call Prisma directly in components or route handlers — always through the service layer
- Never use 'any' type — use 'unknown' and narrow with type guards
- Never write raw SQL — always use Prisma's query builder
- Never use React.FC type annotation — just type props directly
- Never import from barrel files in tests — import directly from the source file to avoid circular dependency issues
Testing conventions
Testing:
- Test runner: Vitest (NOT Jest — do not write Jest-style imports)
- Testing library: @testing-library/react for component tests
- Test files: colocated with source files as *.test.ts or *.spec.ts
- Mock pattern: use vi.mock(), not jest.mock()
- Factory functions for test data in src/tests/factories/*.ts — never create test data inline
- Integration tests in src/tests/integration/ — these hit the test database
Cursor will write import { jest } from '@jest/globals' in a Vitest project if you don't tell it otherwise. This one rule prevents that.
What to put in a CLAUDE.md file
CLAUDE.md covers everything .cursorrules does, plus Claude Code-specific context: the full project structure, custom CLI commands, deployment workflow, and anything a new team member would need to orient themselves.
The CLAUDE.md for a Python FastAPI service:
# Project: Payments API
## Stack
- Python 3.12
- FastAPI 0.110 with Pydantic v2
- SQLAlchemy 2.0 (async) with Alembic for migrations
- PostgreSQL 16
- Redis for caching and job queues
- Celery for background tasks
- pytest + pytest-asyncio for tests
## Directory layout
src/
api/ # Route handlers (thin — delegate to services)
services/ # Business logic layer
repositories/ # Database access layer (SQLAlchemy queries here only)
models/ # SQLAlchemy ORM models
schemas/ # Pydantic request/response schemas
tasks/ # Celery task definitions
core/ # Config, database session, dependencies, exceptions
tests/
unit/ # Fast tests, no database
integration/ # Requires running test database (see Makefile)
## Patterns
- Route handlers call services. Services call repositories. Repositories call SQLAlchemy.
- Never call the database from a route handler directly.
- All exceptions inherit from AppException in core/exceptions.py
- Use dependency injection for database sessions: `db: AsyncSession = Depends(get_db)`
- Background tasks go in Celery, not FastAPI BackgroundTasks (we've had reliability issues)
## Commands
make dev # Start dev server with hot reload
make test # Run all tests
make test-unit # Unit tests only (fast)
make migrate # Apply pending migrations
make migration m="your message" # Create new migration
## Deployment
- Staging: merge to `develop` branch triggers GitHub Actions → deploys to staging
- Production: create a release tag (v*.*.*) → deploys to production
- Never push directly to main — PRs only
- Migrations run automatically on deploy. Destructive migrations need manual approval.
## Never do these
- Never use synchronous SQLAlchemy in async routes
- Never commit .env files — use .env.example as the template
- Never write business logic in Celery tasks — tasks call services
- Never skip Alembic for schema changes — no raw DDL
The "Commands" section is particularly useful. Claude Code can run terminal commands, and knowing your Makefile means it can run make test instead of guessing at the pytest command.
A step-by-step example: Next.js + TypeScript + Prisma
Here's a starter .cursorrules you can adapt:
Project: [Your Project Name]
Stack:
- Next.js 15 (App Router)
- TypeScript 5.4 (strict mode)
- Prisma 5.x + PostgreSQL
- Tailwind CSS v4
- shadcn/ui in src/components/ui/
- next-auth v5
Directory structure:
src/
app/ # Next.js App Router pages
components/ # React components
ui/ # shadcn/ui primitives (do not modify)
lib/ # Shared utilities
services/ # Database and business logic
schemas/ # Zod schemas
prisma/
schema.prisma
migrations/
Architecture rules:
- All Prisma calls in src/services/ — never in components, never in route handlers
- Zod schemas for all form inputs and API responses
- Server Actions for form handling (not API routes)
- API routes only for webhooks and external integrations
Code style:
- Named exports only
- Async/await, no .then()
- Imports: external → ~/lib, ~/services → relative
- Error class: use AppError from ~/lib/errors
Never:
- Default exports
- Direct Prisma calls outside services/
- console.log (use our logger or remove before PR)
- 'any' type
- Pages Router patterns in App Router context
Keeping the files updated
Project memory files go stale if you don't treat them as living documentation. The maintenance rule: when you catch the AI making the same mistake twice, add a "never do this" rule.
Practical triggers for updating:
- You add a new package or library to the project
- You establish a new architectural pattern (service layer, new repository, new abstraction)
- You find yourself repeating a correction in 3 different sessions
- A new team member joins and asks a question you realize isn't documented
The best time to add a rule is immediately after you catch the mistake, while the context is fresh. Create a habit: end every AI coding session by asking "did I correct something the AI did wrong?" If yes, add a rule before closing the editor.
The 10x multiplier
The ROI on these files is asymmetric. A .cursorrules file takes 30-60 minutes to build well. It then saves those 30-60 minutes every single week — spread across dozens of micro-corrections that no longer happen.
More importantly, it changes what you can delegate to the AI. Without project memory, you have to review every output carefully for things that violate your conventions. With project memory, the AI already knows your conventions and violations become rare. The review task shifts from "is this code correct for our project?" to "is this code correct for this problem?" That's a much faster review.
The files also compress team knowledge. A new developer who reads your .cursorrules file understands the architectural philosophy of the project in 5 minutes. Every convention, every "never do this," every pattern — documented, attached to the code, not living in someone's head.
One last thing: don't try to make these files comprehensive on day one. Start with the stack, 5 architectural rules, and 5 "never do" rules. Run it for a week. Add what's missing based on what actually came up. A tight, accurate memory file beats a bloated one that's 30% wrong.



