Claude Code CLAUDE.md Guide — Project Memory & Persistent Instructions
CLAUDE.md is the most underused Claude Code feature. It's a plain Markdown file that Claude reads at the start of every session — your project's "permanent memory." Once written, Claude always knows your stack, your conventions, and how to run your project without you repeating it every time.
What CLAUDE.md Does
Every time you run claude in a project directory, Claude Code automatically reads any CLAUDE.md file it finds — in the current directory and in parent directories up to the home folder. The contents become part of Claude's permanent context for that session.
Without CLAUDE.md, you start every session by explaining your tech stack, your test commands, your code style. With CLAUDE.md, Claude starts already knowing all of that.
Where to Put CLAUDE.md
Claude Code looks for CLAUDE.md files in this order:
- Project root —
/your-project/CLAUDE.md— the main project-wide file - Subdirectories —
/your-project/frontend/CLAUDE.md— area-specific context - Home directory —
~/.claude/CLAUDE.md— global preferences that apply to all projects
Claude reads all applicable CLAUDE.md files and merges them. The most specific one (closest to the file being edited) takes precedence on conflicts.
What to Include in CLAUDE.md
1. Tech Stack (essential)
What language, framework, and key libraries you use. Claude defaults to safe guesses without this, but explicit > implicit.
2. Dev Commands (essential)
How to start, test, lint, build, and deploy. These come up constantly — having them in CLAUDE.md means Claude can run the right commands without asking.
3. Coding Conventions
Your style rules that aren't captured by a linter: naming patterns, error handling approach, whether you prefer async/await vs callbacks, preferred import style, etc.
4. Architecture Overview
A brief description of the key directories and what lives where. Helps Claude navigate the codebase without opening every file to find what it needs.
5. Areas to be Careful With
The parts of the codebase that are fragile, have external dependencies, or that only certain people should modify. Saves Claude from "helpful" changes that break prod.
6. Custom Slash Commands
If you've defined custom commands in .claude/commands/, list them here so Claude knows they exist and when to suggest using them.
CLAUDE.md Templates
Node.js / TypeScript Project
# Project: MyApp API ## Stack - Node.js 20, TypeScript 5.4, Express 5 - PostgreSQL 16 (via Drizzle ORM) - Vitest for testing, ESLint + Prettier for linting ## Dev Commands ``` npm run dev # start dev server (port 3000) npm test # run test suite npm run lint # ESLint + type-check npm run db:migrate # run pending migrations npm run build # compile TypeScript to dist/ ``` ## Conventions - Use `async/await` (never raw Promises or callbacks) - Controller functions are thin; business logic lives in `src/services/` - All DB queries go through `src/db/` — never use raw SQL outside that directory - Error handling: throw typed errors from services, catch in controllers, return structured JSON errors - Imports: use absolute paths from `src/` (configured in tsconfig paths) ## Architecture - `src/routes/` — Express routers (thin, just validation + service calls) - `src/services/` — business logic - `src/db/` — Drizzle schema + queries - `src/middleware/` — auth, logging, rate limiting - `tests/` — mirror the `src/` structure ## Do Not Touch - `src/auth/jwt.ts` — security-critical, requires security review - Database schema migrations — always create a new migration, never edit existing ones
Python / Django Project
# Project: Django Backend ## Stack - Python 3.12, Django 5.0, DRF (Django REST Framework) - PostgreSQL via psycopg3 - pytest-django for testing - Black + isort + mypy for code quality ## Dev Commands ``` python manage.py runserver # dev server pytest # run tests python manage.py makemigrations # create migration python manage.py migrate # apply migrations black . && isort . && mypy . # format + type-check ``` ## Conventions - All API views use DRF class-based views (APIView or ViewSet) - Type annotations required on all function signatures (mypy strict) - Models: snake_case fields, no `null=True` on CharFields (use empty string) - Serializers live in `app/serializers.py`, not in views - Tests: use `pytest.mark.django_db` for DB tests, factory_boy for fixtures ## Architecture - `apps/` — Django apps (users, products, orders, etc.) - `config/` — settings, urls, wsgi - `tests/` — pytest test files organized by app ## Environment - Use `.env` for secrets (django-environ), never hardcode - Dev settings in `config/settings/dev.py`, prod in `prod.py`
React / Next.js Project
# Project: Marketing Site (Next.js) ## Stack - Next.js 15 (App Router), TypeScript, Tailwind CSS 4 - shadcn/ui components, Radix UI primitives - Zustand for state, React Query for server state - Vitest + Testing Library for tests ## Dev Commands ``` npm run dev # start dev server (port 3000) npm test # run unit tests npm run e2e # run Playwright end-to-end tests npm run build # production build npm run lint # ESLint check ``` ## Conventions - Components: functional only, no class components - Styling: Tailwind classes only, no custom CSS files (exception: globals.css) - State: server state in React Query, client-only in Zustand - File naming: PascalCase for components, kebab-case for pages/routes - Exports: named exports from components, default exports from pages ## App Router Structure - `app/` — routes and layouts (file-based routing) - `components/` — shared UI components - `components/ui/` — shadcn/ui generated components (don't edit these manually) - `lib/` — utilities and API clients - `hooks/` — custom React hooks ## Performance Rules - Images: always use `` from next/image, never ` ` - Fonts: use next/font, never @import in CSS - Heavy components: lazy load with `dynamic(() => import(...))`
Advanced CLAUDE.md Patterns
Custom slash commands
Create project-specific slash commands by adding Markdown files to .claude/commands/:
mkdir -p .claude/commands # Create a /review command cat > .claude/commands/review.md << 'EOF' Review the staged git changes for: 1. Logic errors and edge cases 2. Security issues (injection, auth bypasses, secrets) 3. Missing error handling 4. Test coverage gaps Output as a bulleted list grouped by severity: Critical, Warning, Info. EOF
Then reference these in CLAUDE.md so Claude knows to suggest using them:
## Custom Commands - `/review` — staged-diff code review (security + correctness) - `/commit` — generate a conventional commit message for staged changes
Hierarchical CLAUDE.md for monorepos
In a monorepo with different stacks, use a root file for shared context and per-package files for specifics:
/CLAUDE.md ← shared: repo structure, CI commands, git conventions /packages/api/CLAUDE.md ← API-specific: routes, DB, auth patterns /packages/web/CLAUDE.md ← Web-specific: components, state, routing /packages/mobile/CLAUDE.md ← Mobile: React Native conventions
Global CLAUDE.md in home directory
Add a ~/.claude/CLAUDE.md for preferences that apply across all your projects:
## My Global Preferences - I prefer explicit over implicit: spell out types, conditions, and return values - Always suggest running tests after making changes - When creating files, always create the corresponding test file - Commit messages: Conventional Commits format (feat:, fix:, chore:, etc.) - Never use `any` in TypeScript — use `unknown` and narrow it - Log the `why`, not the `what` in commit messages
What NOT to Put in CLAUDE.md
- Secrets, API keys, passwords — CLAUDE.md is committed to git. Never put credentials here.
- Every file path in the project — Claude can read the file system. A brief architecture overview is useful; a complete file tree is noise.
- Information that's already in other files — if your style is enforced by a .eslintrc, you don't need to repeat every rule in CLAUDE.md. Just note "ESLint enforces our style — run lint before finishing."
- Very long documents — CLAUDE.md consumes tokens. Aim for under 2,000 words. For long architecture docs, link to them: "See ARCHITECTURE.md for details."
CLAUDE.md vs .claude/settings.json
These serve different purposes:
- CLAUDE.md — human-readable context and instructions. What Claude should know and how it should behave in your project.
- .claude/settings.json — machine-readable configuration. Which tools are auto-approved, which are blocked, environment variables, hooks.
Use CLAUDE.md for "describe the project and conventions." Use settings.json for "allow/deny specific actions."
Frequently Asked Questions
Does CLAUDE.md use extra tokens?
Yes, but less than you think. CLAUDE.md is included in the system prompt, which is automatically cached by Anthropic's prompt caching. After the first call in a session, you pay ~10% of normal cost for that cached content. A 1,000-word CLAUDE.md costs roughly $0.001–0.003 per session — negligible.
Can I put CLAUDE.md in a .gitignore'd location?
Yes. If you have secrets-adjacent context you don't want in git, create a CLAUDE.local.md (gitignored) alongside your CLAUDE.md. Claude reads both. Put public context in CLAUDE.md (committed) and private context in CLAUDE.local.md (gitignored).
What's the maximum size for CLAUDE.md?
There's no hard limit, but Claude Code's context window is 200K tokens. Practically, keep CLAUDE.md under 2,000 words for best results. Very large CLAUDE.md files can push useful project files out of the context window.
How do I test if CLAUDE.md is being read?
Start a session and ask: "What tech stack am I using?" or "What command runs the tests?" If Claude answers correctly without reading any files, CLAUDE.md is working. You can also use /status to see what context Claude has loaded.