The Complete CLAUDE.md Guide: Best Practices, Templates, and Token Cost in 2026
5,000-token CLAUDE.md files cost $30+/month in overhead. Learn the cascade pattern, what belongs in CLAUDE.md, templates for solo/team/monorepo, and how to keep it lean.
Every Claude Code session starts by reading CLAUDE.md before your first message. That file gets sent to Anthropic on every single turn, attached to every single request, for the entire session. Most developers write it once, forget about it, and never audit what that costs. A bloated CLAUDE.md silently inflates every API call, not just at startup, but on every tool call, every file read, every message in a multi hour session.
Source: Anthropic CLAUDE.md documentation, accessed May 2026
TL;DR
- CLAUDE.md is a system-prompt-as-file that Claude Code reads and re-sends on every turn.
- Keep it under 600 tokens: project stack, hard rules, and custom workflows only.
- Use subdirectory CLAUDE.md files for monorepos.
- A
session-notes.mdhandles transient context so your main file stays lean.
What Is CLAUDE.md and Why It Matters
CLAUDE.md is the file Claude Code reads at the start of every session to understand the project it is operating in. It functions as a persistent system prompt: instructions that do not change from session to session and that the model should treat as authoritative throughout its work. Think of it as the onboarding document you would hand a new developer, except Claude reads it on every turn, not just on the first day.
The loading mechanism is simple. When you invoke Claude Code in a directory, it looks for a CLAUDE.md file at the project root. That file's contents are prepended to the system prompt for the conversation. They are not cached between sessions, not summarized, and not shortened, the full text goes into the context window on every API request. This makes CLAUDE.md different from a README: a README gets read once by a human; CLAUDE.md gets read by the model on every turn, at your expense.
A well structured CLAUDE.md is the difference between a model that works the way you want from the first message and one that you have to re-educate session after session. The cost is not just dollars, it is the time you spend correcting style, workflow, and security issues that a good CLAUDE.md would have prevented.
The file name matters. Claude Code specifically looks for CLAUDE.md (all caps) at each directory level in the cascade. A file named claude.md or Claude.md in a case sensitive filesystem will not be picked up. On Windows, case is ignored and both will load, but keep the name canonical to avoid surprises when the project runs on Linux CI. The file uses standard Markdown syntax, headers, lists, code blocks, and Claude parses it as structured text, not as raw instructions. Headers help Claude identify different sections of your guidance and apply them in context.
How CLAUDE.md Loads: The Cascade (Global → Project → Subdirectory)
Claude Code loads CLAUDE.md files from three locations, in this order, stacking them into a single context block:
- Global (
~/.claude/CLAUDE.md), your personal preferences, cross project conventions, tools you always use - Project root (
<repo>/CLAUDE.md), committed to version control, shared with the team, project specific rules - Subdirectory (
<repo>/packages/api/CLAUDE.md, etc.), scoped rules that apply only when Claude operates within that subtree
All three levels stack in context for every turn. If you have a 200-token global CLAUDE.md, a 400-token project CLAUDE.md, and a 150-token subdirectory CLAUDE.md, every API call in that subdirectory carries 750 tokens of instruction overhead, before your conversation even starts.
The cascade is additive, not overriding. Subdirectory rules do not replace project rules; they extend them. This design is intentional: the global file handles personal preferences without polluting shared files; the project file handles team wide conventions; the subdirectory file handles per package specifics. The three levels do not conflict when each file stays in its lane.
One practical implication: if you write a rule in your global CLAUDE.md and the same rule appears in the project CLAUDE.md, Claude will see it twice. Duplication is not harmful, the model reconciles identical instructions, but it wastes tokens. Audit the three levels periodically and remove rules that are stated at multiple levels when the lower level file already covers them. The global file should contain only rules that are not already in the project file.
Source: Anthropic CLAUDE.md documentation, cascade loading behavior, accessed May 2026
The Token Cost of a Bloated CLAUDE.md
Here is the math that most developers have never run. CLAUDE.md is not a one time cost, it is a recurring charge on every API call in every session. A file that looks harmless when you write it becomes a significant line item when you multiply it by the number of turns in a session, the number of sessions in a day, and the number of developers on the team.
A 5,000-token CLAUDE.md at Sonnet's current input rate of $3 per million tokens costs $0.015 per API request:
5,000 / 1,000,000 × $3.00 = $0.015 per request
That is not per session, it is per API request. A typical 30-turn Claude Code session sends 30 requests. That means a single session costs $0.45 in CLAUDE.md overhead alone.
At 2,000 sessions per month across a team (roughly 10 developers running 200 sessions each), that is $30+/month in pure context overhead. Nothing useful computed. No tool results. No code. Just your instruction file being re-sent, over and over, because it was never trimmed.
Compare that to a lean CLAUDE.md:
- 300-token CLAUDE.md (well structured): $0.0009 per request → $0.027 per 30-turn session → $54/month at 2,000 sessions
- 5,000-token CLAUDE.md (bloated): $0.015 per request → $0.45 per 30-turn session → $900/month at 2,000 sessions
The difference is $846/month, for the same developer productivity, the same number of sessions, the same work. The only variable is CLAUDE.md size.
The 300-600 token range is not arbitrary. Sourcegraph's analysis of high performing AI development workflows and Anthropic's own CLAUDE.md guidance both converge on this range as the effective sweet spot. Below 300 tokens and the file is too thin to be useful. Above 600 tokens and you are likely storing content that belongs somewhere else.
Source: Anthropic CLAUDE.md documentation and Sourcegraph developer AI workflow research, accessed May 2026
What Belongs in CLAUDE.md vs What Doesn't
The clearest sign of a bloated CLAUDE.md is that it contains information Claude can get itself, or information that changes between sessions.
What belongs in CLAUDE.md:
- Project tech stack: language, runtime version, framework, key dependencies
- Coding conventions: indentation, import style, naming patterns, what to avoid
- Security hard rules: things Claude must never do regardless of what you ask
- Custom commands and workflows: how to run tests, build, lint; project specific scripts
- Architecture decisions: why you chose a pattern and what alternatives to avoid
What does not belong in CLAUDE.md:
- Task state or current progress ("we are working on the auth refactor")
- Session notes or blockers from the last session
- Content from your README that Claude can read directly
- Exhaustive style guides that amount to 500 lines of copy paste from your linter config
- Dependency lists (Claude can run
npm ls,pip list, orcat package.json) - Personal preferences that only apply to you and not your team
The distinction is between rules that are durable and shared vs context that is transient and personal. Durable rules belong in CLAUDE.md. Transient context belongs in session-notes.md (more on that in a moment). Personal preferences belong in your global ~/.claude/CLAUDE.md, not in the committed project file.
A quick audit test for any line in your CLAUDE.md: "Will this still be true and relevant in six months?" If yes, it belongs. If it might be outdated (current sprint focus, a dependency you are evaluating, a temporary workaround), it does not. Apply this test line by line when your CLAUDE.md starts growing past 600 tokens, and you will typically find that 30-40% of the content fails it. Cut those lines, your next session will be cheaper and your model will have a cleaner signal to work with.
Writing Effective Rules: Structure, Voice, and Specificity
Bad rules are vague. Good rules are specific enough that Claude cannot misinterpret them.
Bad: "Write clean code."
Good: "Use 2-space indentation. Prefer named exports over default exports. Never use any in production TypeScript, use unknown and narrow it."
Bad: "Follow security best practices."
Good:
- Never commit secrets, API keys, or credentials to version control
- Never run destructive git commands (
reset --hard,push --force,branch -D) without explicit user confirmation - Never implement dynamic plugin loaders or
eval-based execution of user supplied code
The specificity difference matters because Claude Code follows instructions literally. A vague rule like "write clean code" gives the model no actionable guidance. A specific rule about indentation, exports, and type safety constrains behavior in measurable ways.
Security Hard Rules
Security rules deserve their own section in CLAUDE.md because the consequences of violating them are asymmetric. Getting a naming convention wrong is a code review comment. Committing a secret or running git push --force main in production is an incident.
Write security rules in the imperative and give them a dedicated section header. Examples that belong in most projects:
- Never commit
.envfiles, private keys, or API tokens - Never run database migrations without a dry run check first
- Never delete files without confirming the path with the user
- Never push to
mainormasterdirectly, always create a branch
The projects where Claude Code behaves most reliably are those where CLAUDE.md states security rules as hard constraints rather than suggestions. "Prefer not to" is different from "never", use "never" when you mean it.
Subdirectory CLAUDE.md Patterns for Monorepos
The cascade pattern becomes especially useful in monorepos, where different packages have genuinely different conventions that should not bleed into each other.
Consider a three package monorepo: api/, web/, and shared/. The root CLAUDE.md handles cross cutting concerns: how to run the test suite, monorepo wide naming conventions, infrastructure hard rules. But the API package uses Express and writes TypeScript at Node 20; the web package is React 19 with strict no-any rules; the shared package exports pure functions with 100% test coverage requirements.
Putting all of this in the root CLAUDE.md creates two problems. First, the file gets bloated with conditional logic ("for the API package, do X; for the web package, do Y"). Second, Claude operating in the api/ subtree does not need to know the React 19 rules, those tokens are overhead.
The fix is straightforward:
- Root CLAUDE.md: monorepo commands, shared git rules, shared TypeScript version, security hard rules
api/CLAUDE.md: Node 20 specifics, Express patterns, database query conventions, API error formatweb/CLAUDE.md: React 19 conventions, component naming, Tailwind class ordering, no-anystrictnessshared/CLAUDE.md: Pure functions only, 100% test coverage required, no side effects in exports
Subdirectory CLAUDE.md is the answer to "my CLAUDE.md is getting too long" before you reach for optimization tools. If your project CLAUDE.md is growing past 800 tokens, ask whether some of those rules are actually package specific. Moving them down the tree keeps each scope lean without losing any of the guidance.
The Session-Notes.md Pattern (End of Session Handoff)
One of the most common CLAUDE.md antipatterns is using it as a running journal. Developers add blockers, decisions, and progress notes to CLAUDE.md because they want Claude to remember them next session. This is the wrong file for that content.
Here is the pattern that works better.
At the end of a productive session, ask Claude to write a session-notes.md in the project root. The content should cover three things: what was decided and why, what is currently blocked and what would unblock it, and the single most important next action to start the next session. This file is explicitly transient, it gets overwritten at the end of each session.
The next session, you do not recap. You say: "Read session-notes.md and continue." Claude reads it, has full context on where you left off, and starts immediately. No re-explaining the architecture decisions from three days ago. No re-establishing why a particular approach was rejected.
The key distinction is why session-notes.md lives outside CLAUDE.md: session notes are transient and session specific; CLAUDE.md rules are permanent and shared. Mixing them inflates your permanent context with temporary information that becomes stale within days.
A common variation on this pattern is a context/ directory in the project root containing multiple files: session-notes.md (updated each session), decisions.md (architectural choices and their rationale), and blockers.md (current blockers and what resolves them). This splits the transient from the durable even within the context files. When you start a new session, you can say "read context/session-notes.md and context/blockers.md" and Claude gets exactly the right scope without loading decisions from three months ago that are no longer relevant. The point is that none of this lives in CLAUDE.md, it lives in files Claude reads on demand.
A minimal session-notes.md template:
## Session Notes, 2026-05-11
### Decisions made
- Chose JWT over session cookies for stateless scaling
- Skipped Redis for now, will add when we need rate limiting
### Current blockers
- Auth middleware needs test coverage before we can merge
- Blocked on: write tests for POST /auth/login and the 401 paths
### Next action
Start with `src/auth/middleware.test.ts`, tests first, then fix the bug in token expiry checkTeam CLAUDE.md: Shared vs Personal Rules
Teams that commit CLAUDE.md to version control face a tension that solo developers do not: whose preferences should the file reflect?
The answer is neither yours nor your colleague's. The committed project CLAUDE.md should reflect team decisions about the codebase, conventions agreed on in code review, architectural rules that protect the project, security requirements that apply to everyone. Personal preferences stay in each developer's global ~/.claude/CLAUDE.md.
The practical split:
Committed project CLAUDE.md (shared, team owned):
- Language and runtime requirements
- Coding conventions already enforced by linter or established in code review
- Security hard rules
- How to run tests, build, deploy
- Architecture decisions with rationale
Personal ~/.claude/CLAUDE.md (private, individual):
- "Always show me the diff before applying changes"
- "Prefer to split large tasks into smaller steps and confirm before proceeding"
- "I use Neovim, format code comments for terminal width, not IDE wrap"
- Style preferences not shared by the team
Mixing personal preferences into the shared CLAUDE.md pollutes the team's context with rules that only one developer cares about. It also creates friction: if two developers have conflicting preferences, the shared file cannot satisfy both. The cascade design exists precisely to solve this, personal preferences go in the global file, project conventions go in the committed file.
One team pattern worth adopting: treat the project CLAUDE.md like your lint config. Any rule that goes into it should have been discussed and agreed on, not added by one developer to reflect their personal style. If you find a colleague has committed a personal preference to the project file ("always ask before refactoring"), open a discussion about whether it reflects a team decision. If it does, keep it with clearer framing. If it is personal, move it to their global file and remove it from the committed one. Keeping this discipline early prevents the file from drifting into a personal preference dump that costs every developer tokens on every session.
CLAUDE.md Templates
Three templates follow. Each stays within the 300-600 token sweet spot. Copy the one closest to your situation and edit from there.
Solo Dev (Single TypeScript Project)
# Project: my-api
## Stack
- Node 20, TypeScript 5.4 (strict), Fastify 4
- PostgreSQL via postgres.js (never use an ORM)
- Vitest for tests
## Conventions
- Named exports only, no default exports
- 2-space indentation
- Types in dedicated `types.ts` files per module
- Never use `any`, use `unknown` and narrow it
## Commands
- `npm run dev`, start local server (port 3080)
- `npm test`, run vitest
- `npm run build`, tsc compile
- `npm run lint`, eslint
## Security rules
- Never commit .env or secrets
- Never run `git push --force` without asking me first
- Never run database migrations without a dry run firstTeam Project (Committed, Shared)
# Project: acme-platform
## Stack
- Node 22, TypeScript 5.5 (strict)
- Next.js 15 (App Router), Tailwind CSS 4
- PostgreSQL + Drizzle ORM
- Vitest + Playwright for tests
## Coding conventions
- Named exports only
- 2-space indentation, no semicolons
- Tailwind: mobile first, no inline styles
- All DB queries go through `lib/db/`, never raw SQL in components
- Error handling: always return typed Result objects, never throw in library code
## Branch rules
- Feature branches from `develop`, merge via PR
- Never push directly to `main` or `develop`
## Commands
- `npm run dev`, start dev server
- `npm test`, vitest unit tests
- `npm run e2e`, playwright end to end
- `npm run build`, production build
- `npm run db:migrate`, run pending migrations (dry run: add --dry run flag)
## Security hard rules
- Never commit .env, secrets, or private keys
- Never run destructive git commands without confirmation
- Never add dependencies without checking bundle size impactMonorepo Root + Subdirectory Pair
Root CLAUDE.md:
# Monorepo: acme-mono
## Packages
- `packages/api`, Express 5, Node 22
- `packages/web`, Next.js 15, React 19
- `packages/shared`, shared types and utilities
## Monorepo commands
- `npm run build` from root, builds all packages in order
- `npm test` from root, runs all test suites
- `npm run lint`, eslint across all packages
## Shared rules
- TypeScript strict mode everywhere
- Named exports only
- No circular dependencies between packages
## Security hard rules (all packages)
- Never commit secrets
- Never push directly to mainPackage level packages/api/CLAUDE.md:
# Package: api
## Stack
- Express 5, Node 22, TypeScript 5.5
- PostgreSQL via postgres.js (raw SQL, no ORM)
- Zod for request validation
## Conventions
- Route handlers in `src/routes/`, one file per resource
- Database queries in `src/db/`, never in route handlers
- Always validate request body with Zod before processing
- Return `{ data, error }` shape from all endpoints
## Commands (run from packages/api)
- `npm run dev`, start API on port 4000
- `npm test`, vitestSource: Template structures validated against Anthropic's guidance on CLAUDE.md best practices and real world monorepo configurations, accessed May 2026
Common Mistakes and How to Fix Them
1. Treating CLAUDE.md as a README clone
Copying your README into CLAUDE.md is the most common source of bloat. The README is for humans reading the repository; CLAUDE.md is for Claude running code. Claude can read the README directly if it needs it. Remove anything from CLAUDE.md that duplicates documentation Claude can fetch itself.
2. Listing every dependency
"We use Express, Zod, postgres.js, dotenv, helmet, cors, pino, vitest, supertest...", Claude can run cat package.json or npm ls and see this instantly. Listing dependencies wastes tokens on information the model can always retrieve on demand. Keep only the one or two dependencies that have non obvious usage patterns.
3. Putting session state in CLAUDE.md
"We are currently refactoring the auth module, the PR is in review, there is a bug in the token refresh logic...", this belongs in session-notes.md, not CLAUDE.md. Session state becomes stale within days. By the time you are three sessions past the auth refactor, this information is noise that costs tokens on every request.
4. Overusing ALL-CAPS for emphasis
ALL-CAPS sections lose signal when everything is shouting. Reserve ALL-CAPS or bold emphasis for the 2-3 rules where the consequence of violation is serious. If every rule is in ALL-CAPS, Claude has no way to know which ones you actually care about most.
5. Skipping the cascade and cramming everything at project root
A 1,200-token project CLAUDE.md that includes React rules for a package that only 2 of 5 developers touch is paying for React context on every API request made by the other 3 developers. Move package specific rules down to subdirectory CLAUDE.md files.
6. Never auditing token cost
Most developers write CLAUDE.md once and never look at the token count. Run wc -w CLAUDE.md and multiply by 1.33 to get a rough token estimate. If you are over 600 tokens, work through the file section by section and ask whether each block passes the test: is this a durable rule that Claude cannot infer? If not, cut it.
7. Personal preferences in the team CLAUDE.md
"Always show me the git diff before applying any changes", this is a personal preference, not a team rule. If your colleague wants to apply changes without reviewing diffs, the committed CLAUDE.md should not block that. Move personal preferences to your global ~/.claude/CLAUDE.md and keep the committed file to team wide decisions only.
How The Distillery Interacts with CLAUDE.md Overhead
CLAUDE.md sits at the front of every Claude Code request, which means it accumulates in the context window alongside tool results, file reads, and conversation history. The Distillery's compression layer reduces the downstream content, shell output, diff bloat, repeated file reads, but CLAUDE.md authoring is upstream of compression. Pair good CLAUDE.md hygiene (under 600 tokens, no transient state, no README clones) with a token aware proxy and you compound savings: the base overhead is lower and the runtime accumulation is compressed. For the upstream side of the problem, see the context engineering guide.
See thedistillery.dev for the proxy that handles the runtime side while you handle the authoring side.
Frequently Asked Questions
How big should CLAUDE.md be?
Under 600 tokens is the practical target. A well structured CLAUDE.md for a real project, stack, conventions, commands, security rules, fits comfortably in 300-600 tokens. If yours is larger, it likely contains content that belongs elsewhere: README content Claude can read directly, session state that should rotate through session-notes.md, or personal preferences that should live in your global ~/.claude/CLAUDE.md. Run wc -w CLAUDE.md and divide by 0.75 for a rough token estimate. Anything over 800 tokens deserves an audit.
Does subdirectory CLAUDE.md replace the project CLAUDE.md?
No, subdirectory CLAUDE.md extends the project CLAUDE.md, not replaces it. Both files load when Claude operates within a subdirectory; the contents stack in context. This is useful because project wide rules (security hard rules, monorepo commands, shared TypeScript conventions) apply everywhere, while package specific rules (React patterns for the web package, SQL style for the API package) apply only where relevant. Use subdirectory CLAUDE.md to add scope specific rules, not to repeat or override what is already in the root file.
Should I commit CLAUDE.md to git?
The project level CLAUDE.md should be committed. It is a shared team artifact that defines how Claude Code works within the project, the same way you commit .eslintrc or tsconfig.json. Committing it ensures every developer and every CI environment gets the same model behavior. Your personal global ~/.claude/CLAUDE.md is different: it reflects individual preferences and should not be committed anywhere. The cascade handles the split correctly when you treat the two files with different ownership.
Can CLAUDE.md hurt Claude Code performance?
A bloated CLAUDE.md reduces output quality in two ways. First, it costs more: each token in CLAUDE.md is sent to Anthropic on every API request, compounding across a full session. Second, and less obviously, it dilutes attention. Research on large language models shows that information buried in the middle of a long context window receives less attention than information at the start or end. A 5,000-token CLAUDE.md pushes your most important rules into the attention blind spot. A shorter, sharper file puts every rule in the high attention zone. You can also cut the recurring cost of that file with prompt caching.
What's the difference between CLAUDE.md and a system prompt?
Functionally, CLAUDE.md is a system prompt delivered via a file on disk. Claude Code reads the file at session start and injects the contents into the system prompt that is sent to the Anthropic API on every request. The practical difference from a traditional API system prompt is persistence: CLAUDE.md persists across sessions without any code change, can be committed to version control, and can cascade across a directory tree. The cost mechanics are identical, every token in CLAUDE.md is billed as an input token on every request, the same as any system prompt token. See The Distillery pricing for how that overhead compounds.
Try it on your own Claude Code sessions.
The Distillery applies these distillations automatically. Free token optimization, forever.