If you've used Claude Code for more than a day, you've probably discovered that the quality of your sessions tracks almost entirely with the quality of your context. CLAUDE.md is where that context lives. This guide is built from real projects—the patterns that hold up, and the ones that collapse the moment a codebase grows beyond a few hundred files.
What CLAUDE.md Actually Does
Claude Code reads CLAUDE.md automatically at the start of every session. It gets injected into the context window before any user prompt. That single fact explains both why it matters and why most CLAUDE.md files underperform: people treat it like documentation when it should function like a briefing note.
A briefing note is:
- Written for the person doing the work, not for posterity
- Focused on what's non-obvious—not what's visible in the code
- Short enough to be read fully, specific enough to be acted on
Your project's README explains what the project does. CLAUDE.md explains how to work on it safely, right now.
The Core Structure
After experimenting across dozens of projects, this structure consistently works:
## Commands
npm run dev # Start development server (port 3000)
npm run typecheck # TypeScript check without emitting
npm run test # Jest with --watchAll=false for CI mode
npm run lint # ESLint; must pass before commit
## Architecture
[One paragraph. Where are the important boundaries? What's the data flow?]
## Boundaries
- Never edit files in /src/generated/ — they're auto-generated by scripts/codegen.ts
- The public API in /src/lib/api.ts must stay backwards-compatible
- Don't install new dependencies without confirming with me first
## Definition of done
A task is complete when:
1. `npm run typecheck` exits 0
2. `npm run test` exits 0 with no skipped tests
3. The specific behavior described in the task is verified
Four sections. That's it to start. You can add more later once you know what Claude keeps getting wrong.
Writing Each Section
Commands
This is the highest-value section. Claude needs to know exactly how to run, check, and test your code. Be literal: include the actual command, not a description of it.
Bad:
## Commands
Run the dev server and tests.
Good:
## Commands
npm run dev # dev server at http://localhost:3000, hot reload enabled
npm run typecheck # TypeScript strict mode, no emit
npm run test # Jest, exits non-zero on failure
npm run test:e2e # Playwright, requires dev server running
docker compose up -d # Starts postgres:5432 and redis:6379
Pay special attention to test commands. The difference between npm test --watch (interactive) and npm test --watchAll=false (CI-safe) has burned many sessions.
Architecture
One or two paragraphs maximum. The goal is to answer: where should I look for X, and what must I not break?
## Architecture
This is a Next.js App Router application with a PostgreSQL database. All database
access goes through /src/lib/db.ts using the `pg` package directly (no ORM). API
routes live in /src/app/api/. Shared UI components are in /src/components/; they
have no server-side logic and can be freely edited.
The subscriber system in /src/lib/newsletter.ts writes to the `subscribers` table.
The admin dashboard at /admin/* is protected by HTTP basic auth set in Caddyfile.
This paragraph answers: where is the database layer, what's the URL structure, where are the components, and what's the auth model. A new engineer reading this can navigate the codebase. That's the bar.
Boundaries
This is where you prevent the most expensive mistakes. List the things that would cause real damage if Claude changed them without thinking:
## Boundaries
- /src/generated/ is auto-generated. Never edit directly.
- /src/lib/api.ts is consumed by external clients. All exports are public API.
- Database migrations go in /db/migrations/ using the existing format. Never ALTER TABLE in app code.
- Don't bump major dependency versions without asking. We pin these intentionally.
- The Caddyfile controls SSL and routing in production. Don't restructure it.
Notice each item says what the rule is and why the rule exists. "Never edit generated files" without explanation invites curiosity. "Never edit generated files — they're overwritten by codegen.ts on every build" is self-enforcing.
Definition of Done
The most-skipped section and often the most valuable. Claude will sometimes try to hand off work early—"here's the change, let me know if it looks good." A definition of done in CLAUDE.md turns this from an ambiguous question into a checklist.
## Definition of done
Implementation is complete when:
1. TypeScript compiles clean (npm run typecheck)
2. Tests pass (npm run test)
3. The specific acceptance criteria from the task are demonstrated, not assumed
4. No console.error or unhandled promise rejections in the running app
For UI work, add:
5. Tested at 375px (mobile), 768px (tablet), 1280px (desktop)
6. Keyboard navigation works for any new interactive elements
What Doesn't Belong in CLAUDE.md
Being selective matters. A CLAUDE.md that tries to explain everything trains Claude to skim it. Things to leave out:
What's already in the code. If your imports make the framework obvious, don't re-explain the framework. If your file names are descriptive, don't describe the file structure in prose.
Generic best practices. "Write clean code" and "follow DRY principles" are noise. Claude knows these.
Historical context. Why you chose Postgres over MySQL in 2019, the migration from Express to Next.js—this belongs in a decision log, not in operational context.
Aspirational standards. If tests aren't actually required to merge, don't list them as a requirement. CLAUDE.md should describe how things are, not how you wish they were.
Advanced Patterns
Multiple CLAUDE.md Files
Claude Code reads CLAUDE.md from any directory it's currently working in. This means you can layer context:
project-root/
CLAUDE.md # Global: commands, architecture, global boundaries
src/
api/
CLAUDE.md # API-specific: endpoint conventions, error formats, auth patterns
components/
CLAUDE.md # UI-specific: design tokens, accessibility requirements
The global file covers project-wide concerns. Sub-directory files cover domain-specific patterns. This keeps each file short and on-topic.
Keeping It Updated
CLAUDE.md has a half-life. Commands change, boundaries shift, new patterns emerge. Two practices help:
Review after every non-trivial session. Ask Claude to flag anything that contradicts or should update CLAUDE.md before ending the session. This adds 30 seconds and catches drift early.
Treat failed sessions as CLAUDE.md feedback. If Claude made a mistake that you'd expect it to avoid with better context—a broken test command, an edit to a protected file, a dependency install without asking—that's a CLAUDE.md gap. Add the clarification immediately.
The "Assume Nothing" Test
Read your CLAUDE.md and ask: could a capable engineer who knows nothing about this project understand what to do and what not to break? If there are gaps, fill them. This is the bar you want to reach.
A Complete Example
Here's a real-world CLAUDE.md for a Next.js + Postgres project:
## Commands
npm run dev # dev server, http://localhost:3000
npm run build # production build (runs typecheck first)
npm run typecheck # tsc --noEmit, strict mode
npm run test # jest --watchAll=false
npm run lint # eslint, must pass before commit
docker compose up -d # postgres on :5432, redis on :6379
docker compose down # stop services
## Architecture
Next.js 15 App Router. PostgreSQL via `pg` (no ORM). Redis for sessions via `ioredis`.
All database access lives in /src/lib/db/. Files are split by domain: db/users.ts,
db/posts.ts, etc. Add new db functions in the appropriate file; never write raw SQL
in route handlers or components.
Auth is cookie-based. The session token is verified in middleware.ts, which runs
before every /api/* and /dashboard/* route.
## Boundaries
- /src/lib/db/ uses parameterized queries. Never build SQL strings with user input.
- /src/types/api.ts exports the public API types. Changing them is a breaking change.
- Don't add new npm packages. Ask first.
- /db/migrations/ uses sequential numbering. Never edit existing migrations.
- Email templates in /src/emails/ use React Email. Keep them in that format.
## Definition of done
1. `npm run typecheck` exits 0
2. `npm run test` exits 0, no skipped tests
3. Task acceptance criteria demonstrated with specific steps, not just "should work"
4. Database changes have a migration in /db/migrations/
This is 26 lines. It fits comfortably in a context window, and it answers the questions that actually come up during coding sessions.
Frequently Asked Questions
How long should CLAUDE.md be?
Under 60 lines to start. The right length is "long enough to cover what's non-obvious, short enough to read in full." Most projects hit a steady state somewhere between 30 and 80 lines.
Should CLAUDE.md be committed to the repository?
Yes. It documents how to work on the project and belongs with the code. Some teams keep a personal CLAUDE.local.md (gitignored) for machine-specific overrides like custom test runners or local database URLs.
What if I have multiple projects with different setups?
Claude Code reads from the working directory, so each project gets its own context. You can also use Claude Code's project settings to persist configurations per-project.
Does Claude Code ever ignore CLAUDE.md?
Not intentionally. But if the file grows very long, or if the instructions conflict with each other, you'll see degraded compliance. The answer is almost always to make the file shorter and more specific, not longer.
Can I include sensitive information like API keys?
No. CLAUDE.md is committed to your repository. Keep secrets in environment variables and .env files, never in CLAUDE.md.