What Is CLAUDE.md?
CLAUDE.md is a Markdown file that Claude Code reads at the start of every session. Its contents are injected directly into the model's context as project instructions — no commands needed, no special syntax beyond Markdown. Claude uses it to understand your project's conventions, commands, and constraints before touching any code.
Place it at the repo root alongside your package.json, Makefile, or go.mod. Claude Code loads it automatically every time you run claude in that directory.
What to Put in CLAUDE.md
The rule: include only what Claude cannot derive by reading the code. Self-evident things (variable names, function signatures, directory structure) belong in the code itself, not CLAUDE.md.
1. Build, Test, and Lint Commands
## Commands
- Install deps: `npm ci`
- Run tests: `npm test` (requires Postgres running — see docker compose)
- Lint: `npm run lint`
- Type-check: `npm run typecheck`
- Build for prod: `npm run build`
2. Architecture Overview
## Architecture
Monorepo managed by Turborepo.
- `apps/api` — Express REST API (Node 20)
- `apps/web` — Next.js 14 frontend (App Router)
- `packages/db` — Prisma schema + generated client
- `packages/shared` — shared TypeScript types
The web app calls /api/* on the same domain in prod (rewrites in vercel.json).
In dev, NEXT_PUBLIC_API_URL=http://localhost:4000.
3. Code Conventions
## Code conventions
- Named exports only — never default exports
- All async functions must be typed with explicit return Promise<T>
- Database access goes through the repository layer (src/repositories/), never direct Prisma calls in route handlers
- No `console.log` in committed code — use the `logger` util (src/lib/logger.ts)
- Tests use vitest; place test files co-located as `*.test.ts`
4. Files and Directories to Leave Alone
## Do not modify
- `src/generated/` — auto-generated by `npm run generate`; run the command and commit output instead
- `migrations/` — create new migration with `npx prisma migrate dev --name <name>`, never edit existing files
- `public/icons/` — managed by the design team; file a Figma export request instead
5. Known Gotchas
## Gotchas
- The test suite hits a real Postgres: `docker compose up -d` before `npm test`
- Environment variables must be in `.env.local` (not .env) — dotenv is configured this way
- Import paths use `~` alias for `src/` — configure in tsconfig.json paths, not package.json
- The `user.createdAt` field is stored as UTC but displayed in the user's timezone — never compare raw timestamps to Date.now()
Complete Example CLAUDE.md Files
Python / FastAPI Project
# CLAUDE.md — Python API
## Commands
- Install: `pip install -e ".[dev]"`
- Test: `pytest -x` (stop on first failure)
- Lint: `ruff check . && ruff format --check .`
- Type-check: `mypy src/`
- Run dev server: `uvicorn app.main:app --reload`
## Architecture
- `src/app/` — FastAPI application, routers split by domain
- `src/app/models/` — SQLAlchemy ORM models
- `src/app/schemas/` — Pydantic request/response schemas (separate from ORM models)
- `src/app/services/` — business logic layer, called by routers
- Tests in `tests/` use pytest-asyncio with an in-memory SQLite test DB
## Conventions
- All endpoints return Pydantic response schemas, not raw ORM objects
- Use `Annotated` dependency injection for DB session: `db: Annotated[Session, Depends(get_db)]`
- Background tasks go in `src/app/tasks/` and are registered via Celery
## Do not modify
- `src/app/migrations/` — use `alembic revision --autogenerate` to create new migrations
Go Service
# CLAUDE.md — Go Service
## Commands
- Build: `go build ./cmd/server`
- Test: `go test ./... -race`
- Lint: `golangci-lint run`
- Generate mocks: `go generate ./...`
## Architecture
- Entry point: `cmd/server/main.go`
- HTTP layer: `internal/handler/` (chi router)
- Business logic: `internal/service/`
- Data layer: `internal/repository/` with interfaces for testability
- Generated code: `internal/mocks/` (do not edit, run go generate)
## Conventions
- Return errors, don't panic — only panic in init() for fatal misconfigs
- All repository methods take a `context.Context` as the first argument
- Structured logging with `slog` (Go 1.21+), key-value pairs only
- Package names match directory names — never alias imports
## Gotchas
- Integration tests require a real Postgres; set TEST_DATABASE_URL before running
- The Makefile `make test-unit` runs only unit tests (no DB dependency)
Monorepo with Sub-Package CLAUDE.md
Root CLAUDE.md:
# CLAUDE.md — Monorepo Root
## Layout
This is a pnpm workspace monorepo.
- `apps/` — deployable applications
- `packages/` — shared internal libraries
- `infra/` — Terraform and Kubernetes configs (do not touch without asking)
## Commands
- Install all: `pnpm install` (from root only)
- Run a package's tests: `pnpm --filter @acme/api test`
- Build all: `pnpm run build`
## Conventions
- Internal packages use `@acme/` scope
- Changesets manages versioning: `pnpm changeset` before merging a feature
Then apps/api/CLAUDE.md for API-specific notes, packages/ui/CLAUDE.md for component library notes, etc. Claude discovers them contextually.
CLAUDE.md Sections at a Glance
| Section | Include? | Why |
|---|---|---|
| Test / lint / build commands | ✅ Always | Claude cannot guess your exact runner |
| Architecture overview | ✅ For non-trivial repos | Prevents navigating wrong directories |
| Code style / conventions | ✅ Non-obvious ones only | Avoids repeated corrections |
| Do-not-touch directories | ✅ Always | Prevents corrupting generated code |
| Known environment gotchas | ✅ Where relevant | Prevents failed test runs |
| Variable / function names | ❌ Skip | Already in the code |
| Full feature descriptions | ❌ Skip | Claude reads the code itself |
| Git history or PRs | ❌ Skip | Use git log instead |
| Team org chart or roles | ❌ Skip | Irrelevant to code tasks |
Tips for Maintaining CLAUDE.md
- Treat it like code. Commit CLAUDE.md to the repo. PR reviews catch outdated commands.
- Add a line when you correct Claude. If Claude guesses wrong about a convention and you correct it, add that convention to CLAUDE.md so future sessions don't repeat the mistake.
- Version your commands. Write "Node ≥ 20, pnpm 9" not just "pnpm install" — the specific versions prevent confusion on new setups.
- Keep it under 500 lines. Every token in CLAUDE.md is consumed on every request. Bloated CLAUDE.md crowds out actual code context.
- Use headings. Claude navigates the file by section; named headings (## Commands, ## Architecture) make it faster to find relevant information.
Frequently Asked Questions
claude command). Claude Code also reads a global ~/.claude/CLAUDE.md for user-level preferences, and nested CLAUDE.md files in subdirectories for component-specific notes. All discovered files are concatenated and injected at session start.