CLAUDE.md — Project Memory
The Problem CLAUDE.md Solves
Every time you start a new Claude Code session, Claude begins with a blank slate. It can read your files and infer a lot about your project, but it does not inherently know your team's conventions, your preferred testing framework, the commands to build and deploy, or the architectural decisions you have made. Without this context, Claude might generate code using CommonJS when you use ES modules, suggest Jest when you use Vitest, or format code in a style that clashes with your linter.
CLAUDE.md is the solution. It is a plain markdown file that Claude loads automatically at the start of every session, giving it persistent project memory. Think of it as an onboarding document for your AI pair programmer -- the same kind of notes you would give a new team member on their first day.
The Memory Hierarchy
Claude Code reads CLAUDE.md files from multiple locations, and each level of the hierarchy adds context. Files loaded later can build on or override earlier ones:
Global level -- ~/.claude/CLAUDE.md applies to every project on your machine. Put your personal preferences here: your preferred language, coding style, editor conventions, and any universal rules.
Project level -- ./CLAUDE.md in your project root. This is the most important file. It contains project-specific context: tech stack, build commands, testing instructions, file structure overview, and team conventions.
Directory level -- ./src/api/CLAUDE.md, ./src/components/CLAUDE.md, and so on. These provide scoped context for specific areas of your codebase. When Claude is working in a particular directory, it picks up the relevant scoped CLAUDE.md automatically.
All three levels merge together, giving Claude a layered understanding of your global preferences, project rules, and directory-specific conventions.
What to Put in Your CLAUDE.md
The most effective CLAUDE.md files cover four areas: project overview, development commands, code conventions, and common patterns. Here is a complete example for a Next.js project:
# Project: SkyDashboard
## Overview
Next.js 14 app with App Router, TypeScript strict mode, Tailwind CSS.
Backend API routes in src/app/api/. PostgreSQL via Prisma ORM.
## Commands
- `npm run dev` — start development server on port 3000
- `npm run build` — production build
- `npm test` — run Vitest test suite
- `npm run test:e2e` — run Playwright end-to-end tests
- `npm run lint` — ESLint + Prettier check
- `npx prisma migrate dev` — run database migrations
## Code Conventions
- Use ES modules (import/export), never CommonJS require
- All components use functional style with TypeScript interfaces for props
- API routes return NextResponse.json() with proper status codes
- Error handling: use custom AppError class from src/lib/errors.ts
- File naming: kebab-case for files, PascalCase for components
- Tests go in __tests__/ directories alongside the code they test
## Architecture
- src/app/ — Next.js pages and API routes (App Router)
- src/components/ — reusable UI components
- src/lib/ — shared utilities, database client, auth helpers
- src/types/ — TypeScript type definitions
- prisma/ — schema and migrations
## Important Patterns
- All database queries go through src/lib/db.ts, never import PrismaClient directly
- Authentication uses NextAuth.js with JWT strategy
- Use Zod schemas for all API input validation
- Server components by default, "use client" only when needed
And here is an example for a Python API project:
# Project: DataPipeline API
## Overview
FastAPI service with SQLAlchemy ORM, Alembic migrations, Redis caching.
Python 3.12, managed with Poetry.
## Commands
- `poetry run uvicorn app.main:app --reload` — development server
- `poetry run pytest` — run test suite
- `poetry run pytest -x -k "test_name"` — run single test
- `poetry run alembic upgrade head` — run migrations
- `poetry run ruff check .` — lint
- `poetry run mypy .` — type checking
## Conventions
- Type hints on ALL function signatures, no exceptions
- Use Pydantic v2 models for request/response schemas
- Async everywhere: all route handlers and database operations are async
- Tests use pytest-asyncio with factory fixtures
- Environment variables loaded via pydantic-settings, never os.getenv directly
What NOT to Put in CLAUDE.md
Keep these out of your CLAUDE.md:
Secrets and credentials. Never put API keys, passwords, or tokens in CLAUDE.md. It is a regular file that gets checked into version control.
Exhaustive file listings. Do not list every file in your project. Claude can read the file tree itself. A high-level architecture overview is far more useful than a 500-line directory dump.
Session-specific context. Do not put things like "we are currently refactoring the auth module." That belongs in your conversation with Claude, not in a persistent file.
Overly verbose documentation. Aim for under 200 lines. Claude has a finite context window, and every line of CLAUDE.md consumes tokens. Be concise and prioritize the information Claude needs most often.
Directory-Scoped Memory
For larger projects, directory-level CLAUDE.md files let you give Claude specialized context for different parts of your codebase. This is especially powerful in monorepos.
# File: src/api/CLAUDE.md
## API Module Rules
- Every route handler must validate input with Zod before processing
- Always return standardized ApiResponse<T> type
- Use middleware for auth checks, never check auth inside handlers
- Rate limiting is applied at the router level
- All database operations must use transactions for write operations
# File: src/components/CLAUDE.md
## Component Guidelines
- Every component must have a corresponding .test.tsx file
- Use composition over prop drilling — prefer React context for shared state
- All components must be accessible (ARIA labels, keyboard navigation)
- Storybook stories are required for any component in the design system
When Claude is editing a file in src/api/, it automatically picks up the API-specific rules. When it moves to src/components/, it loads the component guidelines instead. This targeted approach prevents rule overload while keeping Claude aligned with your conventions in every part of the codebase.
Auto-Memory and the /memory Command
Claude Code can also learn your preferences over time through auto-memory. When you correct Claude during a session -- "no, we use tabs not spaces" or "always add error handling to async functions" -- Claude may offer to save that preference to your CLAUDE.md.
You can control this behavior with the /memory command:
# Toggle auto-memory on or off
/memory
# Manually add a memory entry
/memory add "Always use vitest instead of jest for tests"
This creates a feedback loop where Claude gets smarter about your project the more you use it. Over time, your CLAUDE.md grows organically based on real corrections and preferences.
The /init Command
If you are starting fresh with Claude Code in an existing project, the /init command provides an interactive way to generate your first CLAUDE.md:
claude
> /init
Claude will analyze your project -- reading package.json, configuration files, directory structure, and existing documentation -- then generate a CLAUDE.md tailored to what it finds. You can review and edit the result before saving.
This is faster than writing a CLAUDE.md from scratch and ensures you do not miss obvious items like build commands and test scripts.
Best Practices
Keep your CLAUDE.md under 200 lines. If it is growing beyond that, split rules into directory-scoped files. Review and update your CLAUDE.md monthly, especially after major refactors or stack changes. Version control it alongside your code so that every team member and every CI/CD run gets the same context.
Write rules as clear imperatives. Instead of "we generally prefer using async/await," write "use async/await for all asynchronous operations, never use raw callbacks or .then() chains." The more explicit you are, the more consistently Claude follows the rule.
Try this exercise: start a new Claude Code session, ask Claude to write a component or function, then review the output for anything that violates your project conventions. For each violation, add a rule to CLAUDE.md, then start a new session and try the same task again. You will see immediate improvement.
Finally, share your CLAUDE.md with your team. When everyone uses the same project memory file, Claude produces consistent output regardless of who is prompting it. This is one of the simplest ways to standardize AI-assisted development across an entire team.