The Complete CLAUDE.md Guide: The Most Important File for Getting Great Results from Claude Code
Introduction
If Claude Code were a new hire on your team, CLAUDE.md would be the employee handbook you hand them on day one. It tells Claude what your project is, how you work, what conventions to follow, and what mistakes to avoid.
In the settings.json Guide, I explained: CLAUDE.md tells Claude "what to do," settings.json tells Claude "how to do it." But here's the thing — settings.json controls permissions, hooks, and model selection. CLAUDE.md controls everything else: your coding standards, architecture decisions, build commands, workflow conventions, and project-specific gotchas.
Of all the configuration files Claude Code reads, CLAUDE.md has the highest impact on output quality. A well-written CLAUDE.md turns Claude from a generic coding assistant into a teammate who understands your project. A poorly written one (or none at all) means you'll spend every conversation re-explaining the same context.
This post covers CLAUDE.md thoroughly — from the five-level file hierarchy to real-world examples, from writing principles to anti-patterns, from the memory system to advanced team patterns.
1. What is CLAUDE.md
1.1 One-Line Definition
CLAUDE.md is a Markdown instruction file that Claude Code automatically reads at startup and injects into its system prompt, giving Claude persistent context about your project, conventions, and workflow.
Every time you start a conversation, Claude Code scans for CLAUDE.md files at multiple levels, merges them, and loads the result into context. You write it once, and it works for every conversation — no more repeating "I'm using Next.js 16 with App Router" or "commit messages should be in English."
Think of it as:
- An onboarding document for your AI teammate
- Your project's "constitution"
- An executable coding standard that Claude actually follows
1.2 How It Differs from Other Config Files
Claude Code has four types of configuration files, each with a distinct role:
| File | Format | Purpose | Analogy |
|---|---|---|---|
CLAUDE.md | Markdown | Project knowledge, coding standards, workflow instructions | Employee handbook |
settings.json | JSON | Permissions, hooks, MCP servers, model, environment variables | Security policy + IT config |
.claude/commands/ | Markdown | Reusable prompt templates (slash commands) | SOP documents |
.claudeignore | Gitignore syntax | Exclude files/directories from Claude's view | Security fence |
A common mistake is stuffing everything into one file. The division is straightforward:
- Natural language instructions → CLAUDE.md
- Structured configuration (permissions, hooks, env vars) → settings.json
- Reusable prompts you trigger manually →
.claude/commands/ - Files Claude should never see →
.claudeignore
If you find yourself writing JSON config blocks in CLAUDE.md, that content belongs in settings.json. If you find yourself writing prose instructions in settings.json, that belongs in CLAUDE.md.
2. File Hierarchy and Loading Order
2.1 The Five Levels
CLAUDE.md has five levels, from highest to lowest priority:
① Enterprise (highest priority, managed by IT)
~/.claude/enterprise/CLAUDE.md
② User-level (personal preferences, all projects)
~/.claude/CLAUDE.md
③ Project root (main project file, committed to Git)
./CLAUDE.md
④ Subdirectory (context-specific, loaded when working in that directory)
./src/CLAUDE.md
./packages/api/CLAUDE.md
⑤ Project user-specific (personal notes for this project)
~/.claude/projects/<project-hash>/CLAUDE.md
The three most commonly used are: User-level (personal preferences), Project root (team-shared), and Subdirectory (module-specific).
2.2 When to Use Each Level
| Level | Location | Committed to Git? | Use Case | Example Content |
|---|---|---|---|---|
| Enterprise | ~/.claude/enterprise/CLAUDE.md | N/A (managed by IT) | Company-wide coding standards | "All code must pass security review" |
| User-level | ~/.claude/CLAUDE.md | No | Personal preferences across all projects | "Respond in English," "Use vim keybindings" |
| Project root | ./CLAUDE.md | Yes | Main project context, team conventions | Tech stack, build commands, architecture |
| Subdirectory | ./src/CLAUDE.md | Yes | Module-specific rules | "Components in this folder use PascalCase" |
| Project user-specific | ~/.claude/projects/<hash>/CLAUDE.md | No | Personal notes for this specific project | "The auth module is flaky, always run tests twice" |
2.3 How Merging Works
Claude Code loads all applicable CLAUDE.md files and concatenates them into a single context block. This is different from settings.json's deep merge — CLAUDE.md files are simply appended together.
The loading order:
1. Enterprise CLAUDE.md (if exists)
2. User-level ~/.claude/CLAUDE.md (if exists)
3. Project root ./CLAUDE.md (if exists)
4. Subdirectory CLAUDE.md files (from root to current working directory)
5. Project user-specific CLAUDE.md (if exists)
When instructions conflict, later-loaded content takes priority because it appears closer to the end of the context. In practice:
Enterprise rules → Cannot be overridden (enforced by the system)
User preferences → Overridden by project rules
Project rules → Overridden by subdirectory rules
Subdirectory rules → Most specific, highest effective priority
Project user notes → Personal overrides for this project
2.4 Visualizing the Hierarchy
Here's how it looks for a developer named Alice working on a monorepo:
~/.claude/enterprise/CLAUDE.md "All commits must reference a Jira ticket"
│
~/.claude/CLAUDE.md "Respond in English, use conventional commits"
│
project/CLAUDE.md "Next.js 16, pnpm, Turborepo monorepo"
│
├── packages/web/CLAUDE.md "React Server Components preferred"
│
├── packages/api/CLAUDE.md "Express + Prisma, REST conventions"
│
└── packages/shared/CLAUDE.md "Pure TypeScript, no framework deps"
│
~/.claude/projects/<hash>/CLAUDE.md "Alice's personal notes: API team uses port 3001"
When Alice works in packages/api/, Claude sees the merged result of: Enterprise + User + Project root + packages/api/CLAUDE.md + Project user-specific. When she switches to packages/web/, the subdirectory context swaps automatically.
3. What to Include (The High-Value Content)
Not all content is equally useful in CLAUDE.md. Some instructions dramatically improve Claude's output; others waste tokens. This section covers the high-value categories, ranked by impact.
3.1 Build, Test, and Lint Commands (Highest Value)
This is the single most impactful thing you can put in CLAUDE.md. Claude needs to know how to verify its own work — run tests, check types, lint code. Without these commands, Claude either guesses (often wrong) or skips verification entirely.
## Commands
- Build: `npm run build`
- Test all: `npm test`
- Test single file: `npm test -- --run path/to/file.test.ts`
- Test single case: `npm test -- --run -t "test name"`
- Lint: `npx eslint . --ext .ts,.tsx`
- Type check: `npx tsc --noEmit`
- Format: `npx prettier --write .`Why this matters: when Claude writes code and then runs npm test, it can catch its own mistakes and fix them in the same conversation. Without the test command, it writes code blindly.
Pro tip: Include the single-test command. Claude often needs to run just one test file, and the syntax varies wildly between test frameworks (jest, vitest, pytest, go test, etc.).
3.2 Code Style and Conventions
Only include conventions that differ from what Claude would assume by default. Claude already knows standard TypeScript conventions, PEP 8, Go formatting, etc. Focus on your project's unique rules.
## Code Style
- Use named exports, not default exports
- Prefer `interface` over `type` for object shapes
- Component files: PascalCase (e.g., `UserProfile.tsx`)
- Utility files: camelCase (e.g., `formatDate.ts`)
- All React components must have explicit return types
- Use `const` arrow functions for components, not `function` declarations
- CSS: use Tailwind utility classes, never write custom CSS unless absolutely necessaryWhat NOT to include:
# Bad — Claude already knows these
- Use meaningful variable names
- Add comments to complex code
- Follow DRY principles
- Use TypeScript for type safety3.3 Architecture Overview
Keep this brief. Claude can read your code — it doesn't need a 200-line architecture document. Focus on the non-obvious structural decisions.
## Architecture
- App Router (Next.js 16): all routes under `app/[locale]/`
- Server Components by default, `'use client'` only when interaction is needed
- Data fetching: Server Components fetch directly, no client-side fetching
- State management: URL search params for shareable state, React context for UI-only state
- i18n: next-intl with `[locale]` dynamic segment, messages in `messages/*.json`Compare this to a bad version:
# Bad — too much detail Claude doesn't need
## Architecture
The application uses Next.js 16 with the App Router pattern. The App Router was
introduced in Next.js 13 and has since become the recommended approach. It uses
React Server Components under the hood, which means components are rendered on
the server by default. This is different from the Pages Router which...
(continues for 50 more lines)3.4 Important Warnings and Gotchas
These are the "don't touch the hot stove" instructions. They prevent Claude from making mistakes that are hard to debug.
## Warnings
- DO NOT modify `middleware.ts` — it contains next-intl routing config that breaks easily
- DO NOT use `useState`/`useEffect` in Server Components — causes hydration errors
- The `Locale` type is exported from `i18n/routing.ts` — always use it instead of `string`
- Tailwind v4 has NO `tailwind.config.js` — configuration is done in CSS with `@import "tailwindcss"`
- The `getSiteUrl()` function in `lib/env.ts` handles all URL construction — never hardcode URLsThese high-signal warnings save entire debugging sessions. Without the Tailwind v4 note, Claude might generate a tailwind.config.js file and wonder why nothing works.
3.5 Git and Workflow Conventions
## Git Conventions
- Commit messages: `type: description` (e.g., `feat: add user profile page`)
- Types: feat, fix, refactor, chore, docs, test, style
- Branch naming: `type/short-description` (e.g., `feat/user-profile`)
- Always create a new branch for features, never commit directly to main
- Do not auto-push — wait for my confirmation
- Do not amend commits unless explicitly asked3.6 Testing Conventions
## Testing
- Framework: Vitest
- Test files: colocated as `*.test.ts` next to source files
- Mocking: use `vi.mock()` for module mocks, `vi.fn()` for function mocks
- Coverage: all utility functions in `lib/` must have tests
- Run tests after every code change to verify nothing broke
- When fixing a bug, write a regression test first3.7 Tech Stack Summary
A concise list of your stack with version numbers. This is especially important when versions have breaking differences (like Tailwind v3 vs v4, or Next.js Pages Router vs App Router).
## Tech Stack
- Next.js 16.1 (App Router)
- TypeScript 5.7 (strict mode)
- Tailwind CSS v4 + @tailwindcss/typography
- next-intl for i18n (locales: zh, en)
- MDX via next-mdx-remote/rsc
- Vitest for testing
- pnpm as package manager3.8 Content Priority Summary
| Category | Impact | Why |
|---|---|---|
| Build/test/lint commands | Highest | Claude can self-verify its work |
| Warnings and gotchas | Very High | Prevents hard-to-debug mistakes |
| Code style conventions | High | Only non-obvious, project-specific rules |
| Tech stack with versions | High | Prevents version-mismatch errors |
| Architecture overview | Medium | Brief context, Claude reads code for details |
| Git/workflow conventions | Medium | Consistency across conversations |
| Testing conventions | Medium | Correct test patterns from the start |
4. Writing Principles
4.1 Be Concise and Direct (Imperative Mood)
CLAUDE.md is instructions, not documentation. Use imperative mood — "do X" not "we usually do X."
| Bad | Good |
|---|---|
| Our team generally prefers to use named exports | Use named exports. No default exports. |
| It would be nice if functions were kept short | Functions must not exceed 50 lines. |
| We typically write tests for new features | Write tests for all new functions. Run npm test to verify. |
| The project uses ESM module format | Use ESM modules. Do not use CommonJS require(). |
Every sentence should be something Claude can act on. If it's not actionable, it probably doesn't belong in CLAUDE.md.
4.2 Prioritize High-Signal Information
Put the most important instructions first. Claude's attention is strongest at the beginning of the context. Structure your CLAUDE.md like an inverted pyramid:
## Commands ← Seen first, used most often
## Warnings ← Critical guardrails
## Code Style ← Daily constraints
## Architecture ← Reference when needed
## Git Conventions ← Used at commit time
## Testing ← Used when writing/running testsIf your CLAUDE.md is long, the instructions at the top get more weight than those at the bottom.
4.3 Don't Repeat What's in the Code
Claude can read your package.json, tsconfig.json, .eslintrc, and every other config file. Don't duplicate that information.
| Don't Write | Why |
|---|---|
| "Dependencies include react, next, tailwindcss..." | Claude reads package.json |
| "TypeScript is configured with strict mode..." | Claude reads tsconfig.json |
| "ESLint rules include no-unused-vars..." | Claude reads .eslintrc |
| "The project has 47 components in the components/ folder..." | Claude can list the directory |
Instead, write things Claude cannot infer:
# Good — Claude can't infer these from config files
- When adding a new route, also update `app/sitemap.ts` and `app/feed.xml/route.ts`
- The `Locale` type must be used instead of `string` for all locale parameters
- CSS variables are defined in `globals.css` — never hardcode color values4.4 Update Incrementally with /memory
You don't need to write the perfect CLAUDE.md on day one. Start small and grow it over time:
- Start with build/test commands and tech stack
- When Claude makes a mistake, add a rule to prevent it
- When you find yourself repeating an instruction, add it to CLAUDE.md
- When a rule never triggers, remove it
The /memory command is your friend here — it appends notes to your project user-specific CLAUDE.md during a conversation. More on this in Section 7.
4.5 Check It into Version Control
Your project root CLAUDE.md should be committed to Git:
git add CLAUDE.md
git commit -m "chore: add CLAUDE.md for AI-assisted development"This way every team member loads the same conventions when using Claude Code. Review CLAUDE.md changes in pull requests — they're as important as your linter config.
What should NOT be committed:
~/.claude/CLAUDE.md(personal, lives outside the repo)~/.claude/projects/<hash>/CLAUDE.md(personal project notes)- Anything containing secrets, tokens, or personal paths
4.6 Use Subdirectory CLAUDE.md for Monorepos
In monorepos or large projects, a single root CLAUDE.md gets unwieldy. Split context into subdirectories:
monorepo/
CLAUDE.md ← Shared: Git conventions, CI commands, monorepo structure
packages/
web/CLAUDE.md ← Frontend: React patterns, component conventions
api/CLAUDE.md ← Backend: API design, database conventions
shared/CLAUDE.md ← Shared lib: pure TypeScript, no framework deps
Claude only loads subdirectory CLAUDE.md files when working in that directory, so this keeps context focused and token-efficient.
4.7 Keep It Under ~500 Lines
CLAUDE.md consumes context window space. Every token spent on CLAUDE.md is a token not available for your actual conversation. Guidelines:
| File | Recommended Length |
|---|---|
| Project root CLAUDE.md | 50–150 lines |
| Subdirectory CLAUDE.md | 20–50 lines |
| User-level ~/.claude/CLAUDE.md | 10–30 lines |
| Total merged result | Under 500 lines |
If your CLAUDE.md exceeds 500 lines, it's time to split into subdirectories or trim low-value content.
5. Anti-Patterns (What NOT to Do)
Knowing what to avoid is just as important as knowing what to include. These are the most common CLAUDE.md mistakes.
5.1 The Anti-Pattern Table
| Anti-Pattern | Problem | Fix |
|---|---|---|
| Writing a novel (2000+ lines) | Wastes tokens, dilutes important info | Keep under 500 lines total, split into subdirectories |
| Stating the obvious | "Use TypeScript" when the project is already TS | Only include non-obvious, project-specific rules |
| Contradicting yourself | "Use named exports" in one section, "use default exports" in another | Review for consistency, single source of truth |
| Including secrets | API keys, tokens, passwords in CLAUDE.md | Use settings.json env field or .env files |
| Micromanaging formatting | "Use 2-space indentation, semicolons at end of lines..." | Let your linter/formatter handle this (Prettier, ESLint) |
| Using it as documentation | Long explanations of how the code works | CLAUDE.md is instructions for Claude, not a README |
| Dynamic/frequently-changing info | "Current sprint: Sprint 47, deadline March 15" | Use chat or /memory for ephemeral context |
| Duplicating config files | Copying tsconfig.json settings into CLAUDE.md | Claude reads config files directly |
5.2 Don't Write a Novel
This is the most common mistake. A 2000-line CLAUDE.md doesn't make Claude smarter — it makes Claude slower and less focused.
# Bad — 2000 lines of this
## Architecture
The application follows a layered architecture pattern inspired by
Domain-Driven Design (DDD). In DDD, the domain layer represents the
core business logic and is independent of infrastructure concerns.
The application layer orchestrates use cases by coordinating between
the domain and infrastructure layers. The infrastructure layer handles
external concerns such as database access, API calls, and file system
operations. This separation of concerns allows us to...
(continues for 200 more lines)# Good — 5 lines that actually help
## Architecture
- Clean Architecture: data → domain → presentation
- Domain layer: pure Dart, no external package imports
- Repository pattern: domain defines interfaces, data implements
- State: Riverpod exclusively (no setState, no Provider)Claude can read your code to understand the details. CLAUDE.md just needs to point it in the right direction.
5.3 Don't Include Obvious Things
If your project is a TypeScript project with a tsconfig.json, Claude already knows you're using TypeScript. Don't waste tokens stating it.
# Bad — Claude already knows all of this
- This project uses TypeScript
- We use React for the frontend
- npm is our package manager
- Git is used for version control# Good — things Claude can't infer
- TypeScript strict mode: all functions must have explicit return types
- React Server Components by default, 'use client' only for interactivity
- pnpm (not npm) — always use pnpm for install/run commands
- Git: conventional commits, never push directly to mainThe difference: the "good" version tells Claude things that change its behavior. The "bad" version tells Claude things it already figured out from reading the codebase.
5.4 Don't Contradict Yourself
In a long CLAUDE.md, it's easy to write conflicting instructions. Claude will follow whichever instruction it sees last (or whichever seems more specific), leading to inconsistent behavior.
# Bad — contradictory
## Code Style
- Use default exports for all components
## Component Conventions
- Always use named exportsReview your CLAUDE.md periodically for contradictions. A good test: could a new team member follow all the instructions without confusion?
5.5 Don't Include Secrets
CLAUDE.md is committed to Git. Never put sensitive information in it.
# Bad — secrets in CLAUDE.md
## API Configuration
- API key: sk-1234567890abcdef
- Database URL: postgres://user:password@host:5432/db
- JWT secret: my-super-secret-keyInstead, use environment variables via settings.json:
// .claude/settings.local.json (not committed to Git)
{
"env": {
"API_KEY": "sk-1234567890abcdef",
"DATABASE_URL": "postgres://user:password@host:5432/db"
}
}5.6 Don't Micromanage Formatting
If you have Prettier, ESLint, or any other formatter configured, let them handle formatting. Don't duplicate those rules in CLAUDE.md.
# Bad — let Prettier handle this
- Use 2-space indentation
- Always use semicolons
- Use single quotes for strings
- Max line length: 100 characters
- Trailing commas in multi-line objects# Good — tell Claude to use the formatter
- Run `npx prettier --write .` after making changes
- All code must pass `npx eslint .` before committingEven better: configure a PostToolUse hook in settings.json to auto-format after every file write.
6. CLAUDE.md vs the Memory System
6.1 How Memory Works
Claude Code has a built-in memory system that complements CLAUDE.md. Understanding the relationship between them is key to using both effectively.
The /memory command saves notes to your project user-specific CLAUDE.md:
~/.claude/projects/<project-hash>/CLAUDE.md
This file is:
- Not committed to Git (it lives outside your project)
- Specific to this project (the path includes a hash of your project directory)
- Personal (only you see it, not your teammates)
- Persistent (survives across conversations)
6.2 The /memory Command
During a conversation, you can tell Claude to remember something:
You: /memory
Claude: What would you like me to remember?
You: The auth module tests are flaky on CI — always run them twice to confirm failures
Claude: I've saved that to your project memory.
Or Claude may automatically suggest saving something to memory when it discovers important project context during a conversation.
What gets saved goes into ~/.claude/projects/<hash>/CLAUDE.md:
# Project Memory
- The auth module tests are flaky on CI — always run them twice to confirm failures
- Port 3001 is used by the API server in development
- The legacy payment module uses CommonJS (exception to the ESM rule)6.3 Memory vs CLAUDE.md vs Chat
Three ways to give Claude context, each with different scope and persistence:
| Method | Scope | Persistence | Shared with Team? | Best For |
|---|---|---|---|---|
| Chat instructions | Current conversation only | Gone when conversation ends | No | One-off instructions, temporary context |
/memory (project user-specific) | This project, all conversations | Persistent across conversations | No | Personal notes, local environment quirks |
| Project CLAUDE.md | This project, all conversations | Persistent, version-controlled | Yes | Team conventions, project standards |
| User-level CLAUDE.md | All projects, all conversations | Persistent | No | Personal preferences (language, style) |
6.4 Priority Order
When instructions conflict, the priority order is:
Chat instructions (highest — explicit in-conversation overrides)
↓
Project user-specific memory (~/.claude/projects/<hash>/CLAUDE.md)
↓
Subdirectory CLAUDE.md (./src/CLAUDE.md)
↓
Project root CLAUDE.md (./CLAUDE.md)
↓
User-level CLAUDE.md (~/.claude/CLAUDE.md)
↓
Enterprise CLAUDE.md (lowest for regular instructions)
This means if you say "use tabs" in chat but your CLAUDE.md says "use spaces," Claude will use tabs for that conversation. The chat instruction wins because it's the most recent and most specific.
6.5 When to Use Each
| Situation | Use |
|---|---|
| "Always respond in English" | User-level ~/.claude/CLAUDE.md |
| "This project uses pnpm, not npm" | Project root CLAUDE.md |
| "Components in this folder use Storybook" | Subdirectory CLAUDE.md |
| "I discovered the API rate limits at 100 req/min" | /memory command |
| "For this task, skip the tests" | Chat instruction |
| "All code must pass security review" | Enterprise CLAUDE.md |
A good rule of thumb: if the information is useful to your team, put it in the project CLAUDE.md. If it's useful to you personally, use /memory. If it's only relevant right now, say it in chat.
7. Real-World Walkthrough: Complete Next.js Monorepo
Let's build a complete multi-layer CLAUDE.md setup for a realistic project: a Next.js monorepo with a web app, an API server, and a shared library.
7.1 Project Context
- Monorepo managed by Turborepo + pnpm workspaces
- packages/web: Next.js 16 frontend (App Router, Tailwind v4, next-intl)
- packages/api: Express + Prisma REST API
- packages/shared: Pure TypeScript utility library
- Team of 4 developers, GitHub for collaboration
- CI/CD via GitHub Actions
7.2 Project Root CLAUDE.md (~60 lines, team-shared)
# E-Commerce Platform
## Tech Stack
- Monorepo: Turborepo + pnpm workspaces
- Language: TypeScript 5.7 (strict mode across all packages)
- CI: GitHub Actions (runs on every PR)
## Commands
- Install deps: `pnpm install` (never use npm or yarn)
- Build all: `pnpm run build`
- Test all: `pnpm run test`
- Test single package: `pnpm --filter <package> test`
- Lint all: `pnpm run lint`
- Type check all: `pnpm run typecheck`
- Format: `pnpm run format`
## Monorepo Structure
- packages/web — Next.js 16 frontend
- packages/api — Express REST API
- packages/shared — Shared TypeScript utilities and types
## Git Conventions
- Commit format: `type(scope): description` (e.g., `feat(web): add product page`)
- Scopes: web, api, shared, ci, root
- Branch naming: `type/scope/short-description`
- Always create PR, never push directly to main
- PRs require 1 approval and passing CI
## Code Standards (All Packages)
- Named exports only, no default exports
- Explicit return types on all exported functions
- No `any` type — use `unknown` and narrow
- Error handling: never swallow errors silently, always log or rethrow
## Warnings
- DO NOT modify `turbo.json` pipeline config without team discussion
- DO NOT add dependencies to root package.json (add to specific packages)
- The shared package must have zero external dependencies
- pnpm-lock.yaml must be committed — never delete or gitignore it7.3 packages/web/CLAUDE.md (Frontend-specific)
# Web Package (Next.js Frontend)
## Tech Stack
- Next.js 16 (App Router) + Tailwind CSS v4
- i18n: next-intl (locales: en, zh; default: en)
- Content: MDX via next-mdx-remote/rsc
## Commands
- Dev server: `pnpm --filter web dev` (don't run this for me)
- Build: `pnpm --filter web build`
- Test: `pnpm --filter web test`
- Test single: `pnpm --filter web test -- --run path/to/file.test.ts`
## Conventions
- Server Components by default, `'use client'` only for interactivity
- Locale params use `Locale` type from `@shared/types`, not `string`
- Tailwind v4: no tailwind.config.js, config via CSS `@import "tailwindcss"`
- CSS variables in `globals.css` — never hardcode colors
- All images use next/image with explicit width/height
## Routing
- All routes under `app/[locale]/`
- Dynamic routes: `app/[locale]/products/[id]/page.tsx`
- API routes: none (use packages/api instead)
## Warnings
- DO NOT modify `middleware.ts` (next-intl routing config)
- DO NOT use `useState`/`useEffect` in Server Components
- DO NOT import from `packages/api` — use HTTP calls via shared API client7.4 packages/api/CLAUDE.md (API-specific)
# API Package (Express + Prisma)
## Tech Stack
- Express 5 + TypeScript
- Prisma ORM (PostgreSQL)
- Zod for request validation
- JWT for authentication
## Commands
- Dev server: `pnpm --filter api dev` (don't run this for me)
- Build: `pnpm --filter api build`
- Test: `pnpm --filter api test`
- DB migrate: `pnpm --filter api prisma migrate dev`
- DB generate: `pnpm --filter api prisma generate`
- DB seed: `pnpm --filter api prisma db seed`
## Conventions
- All routes in `src/routes/` — one file per resource
- Route handlers: thin controllers, business logic in `src/services/`
- All request bodies validated with Zod schemas in `src/schemas/`
- All responses follow `{ success: boolean, data?: T, error?: string }` format
- Error handling: throw `AppError` (from `src/utils/errors.ts`), caught by global middleware
## Database
- Prisma schema in `prisma/schema.prisma`
- Migrations committed to Git
- After schema changes: run `prisma migrate dev`, then `prisma generate`
- Never modify existing migrations — create new ones
## Warnings
- DO NOT expose Prisma client directly in route handlers — use services
- DO NOT store passwords in plain text — use bcrypt (already configured)
- DO NOT modify the auth middleware in `src/middleware/auth.ts` without review7.5 User-level ~/.claude/CLAUDE.md (Personal preferences)
## My Preferences
- Respond in English
- Code comments in English
- Git commit messages in English
- Don't auto-push, wait for my confirmation
- Don't auto-commit, show me the diff first
- Prefer concise explanations over verbose ones7.6 Project User-Specific Memory (Personal notes via /memory)
# Project Memory
- The API dev server runs on port 3001, web on port 3000
- Prisma migrations are slow on my machine — give them 30 seconds
- The `products` table has a full-text search index, use `@@fulltext` in queries
- Alice owns the auth module, check with her before modifying
- The staging database URL is in 1Password under "E-Commerce Staging DB"7.7 The Merged Effective Result
When working in packages/api/, Claude sees all layers merged:
[Enterprise rules, if any]
+
[Personal preferences: English, no auto-push, concise]
+
[Root CLAUDE.md: monorepo structure, Git conventions, shared standards]
+
[packages/api/CLAUDE.md: Express conventions, Prisma rules, API patterns]
+
[Personal memory: port 3001, Prisma slow, Alice owns auth]
The result: Claude knows the monorepo structure, follows team Git conventions, uses Express/Prisma patterns correctly, respects personal preferences, and remembers project-specific quirks — all without you saying a word in chat.
8. Advanced Patterns
8.1 Conditional Instructions
You can write context-dependent instructions that only apply in specific situations. Claude is good at understanding conditional language:
## Testing
- When writing tests, always include both happy path and error cases
- When fixing a bug, write a regression test before writing the fix
- When adding a new API endpoint, add integration tests in `tests/integration/`
- When modifying database schemas, verify migrations with `prisma migrate dev`
## Code Review
- When reviewing a PR, check for: type safety, error handling, test coverage
- When the PR touches auth code, flag it for security reviewThis pattern is more useful than unconditional rules because it gives Claude the right instruction at the right time, without cluttering every interaction.
8.2 Referencing External Docs
CLAUDE.md should be concise, but your project may have detailed documentation elsewhere. Reference it:
## Architecture
- High-level overview: see `docs/architecture.md`
- API design decisions: see `docs/adr/` (Architecture Decision Records)
- Database schema diagram: see `docs/db-schema.png`
- Deployment process: see `docs/deployment.md`Claude can read these files when it needs the details, keeping your CLAUDE.md lean. This is much better than copying 500 lines of architecture docs into CLAUDE.md.
8.3 Team Onboarding
One of the most underrated benefits of CLAUDE.md: new team members get project context instantly. When a new developer joins and starts using Claude Code, they get the same conventions, commands, and guardrails as everyone else.
This is especially powerful combined with the Custom Slash Commands Guide:
.claude/commands/
onboard.md "Explain the project structure and key conventions"
new-feature.md "Walk me through creating a new feature module"
debug-ci.md "Help me debug a failing CI pipeline"
New team members can run /onboard on day one and get a guided tour of the project, powered by the context in CLAUDE.md.
8.4 CI/CD Integration
Claude Code can run in headless mode for CI/CD pipelines, and it reads CLAUDE.md just like in interactive mode. This means your CLAUDE.md conventions are enforced even in automated workflows.
# In a GitHub Actions workflow
claude --headless --message "Review the changes in this PR for code quality issues"Claude reads your CLAUDE.md, understands your conventions, and reviews the PR accordingly. You can add CI-specific instructions:
## CI/CD Notes
- In CI, always run the full test suite: `pnpm run test`
- Build must succeed with zero warnings (treat warnings as errors)
- Type check must pass: `pnpm run typecheck`
- Lint must pass: `pnpm run lint`For CI-specific settings (permissions, model), use the session scope in settings.json:
claude --headless --settings ci-settings.json --message "..."See the settings.json Guide Section 2 for details on session-level configuration.
8.5 Monorepo Strategies
For large monorepos, a layered CLAUDE.md strategy keeps context focused:
Strategy 1: Feature-based splitting
monorepo/
CLAUDE.md ← Global: Git, CI, shared standards
features/
auth/CLAUDE.md ← Auth: security patterns, JWT conventions
payments/CLAUDE.md ← Payments: Stripe API, idempotency rules
notifications/CLAUDE.md ← Notifications: queue patterns, templates
Strategy 2: Layer-based splitting
monorepo/
CLAUDE.md ← Global: Git, CI, shared standards
src/
domain/CLAUDE.md ← Domain: pure business logic, no deps
application/CLAUDE.md ← Application: use cases, orchestration
infrastructure/CLAUDE.md ← Infrastructure: DB, APIs, external services
presentation/CLAUDE.md ← Presentation: React, components, styling
Strategy 3: Package-based splitting (most common)
monorepo/
CLAUDE.md ← Global: Git, CI, monorepo structure
packages/
web/CLAUDE.md ← Frontend conventions
api/CLAUDE.md ← Backend conventions
mobile/CLAUDE.md ← Mobile conventions
shared/CLAUDE.md ← Shared library rules
Choose the strategy that matches your project's organizational structure. The key principle: each CLAUDE.md should contain only the context relevant to that directory.
8.6 Version Control Best Practices
Treat CLAUDE.md changes like code changes:
# In your PR template or review checklist:
- [ ] If conventions changed, CLAUDE.md is updated
- [ ] If new tools/commands added, CLAUDE.md reflects them
- [ ] CLAUDE.md changes reviewed by at least one team memberPractical tips:
| Practice | Why |
|---|---|
| Review CLAUDE.md changes in PRs | Prevents contradictions, maintains quality |
| Update CLAUDE.md when you update linter/formatter config | Keeps instructions in sync with tooling |
| Add CLAUDE.md to your "new project" checklist | Start every project with good AI context |
| Periodically audit CLAUDE.md (monthly) | Remove stale rules, add missing ones |
| Use Git blame on CLAUDE.md | Understand why each rule was added |
8.7 Using /init for Bootstrap
If you're starting from scratch, Claude Code's /init command generates a CLAUDE.md draft by analyzing your project:
claude
> /initClaude will scan your package.json, config files, directory structure, and existing code to generate a starting CLAUDE.md. It's not perfect, but it's a solid starting point that you can refine.
After /init, review the generated file and:
- Remove obvious/redundant information
- Add project-specific warnings and gotchas
- Add your team's Git and workflow conventions
- Verify the commands are correct
9. Frequently Asked Questions
Q1: How long should my CLAUDE.md be?
The sweet spot for a project root CLAUDE.md is 50–150 lines. Under 50 and you're probably missing important context. Over 200 and you're likely including low-value information that dilutes the important stuff. If you need more, split into subdirectory CLAUDE.md files.
The total merged result across all levels should stay under ~500 lines. Beyond that, you're consuming significant context window space.
Q2: CLAUDE.md or README.md — what's the difference?
README.md is for humans reading your GitHub repo. CLAUDE.md is for Claude Code working in your project. They serve different audiences and should contain different content.
| README.md | CLAUDE.md | |
|---|---|---|
| Audience | Human developers, users | Claude Code AI |
| Tone | Explanatory, welcoming | Imperative, concise |
| Content | What the project does, how to install, how to contribute | How to build/test, coding conventions, warnings |
| Length | As long as needed | Under 150 lines |
| Format | Narrative, badges, screenshots | Bullet points, commands, rules |
Some overlap is natural (both might mention the tech stack), but don't just copy your README into CLAUDE.md.
Q3: Claude doesn't seem to follow my CLAUDE.md instructions. Why?
Common causes:
- Instructions too vague — "Write good code" is less effective than "Functions must not exceed 50 lines." Be specific and actionable.
- Contradictory rules — Check for conflicting instructions across different sections or CLAUDE.md levels.
- Context window pressure — If your CLAUDE.md is very long and the conversation is also long, earlier CLAUDE.md content may get less attention. Put critical rules at the top.
- Chat overrides — Explicit instructions in the conversation take priority over CLAUDE.md. If you said something contradictory in chat, that wins.
- Wrong file location — Make sure your CLAUDE.md is in the project root (not in a subdirectory) if you want it to always load.
Q4: Should I put CLAUDE.md in .gitignore?
No — the project root CLAUDE.md should be committed to Git so your team shares the same conventions. Files that should NOT be committed:
~/.claude/CLAUDE.md(personal, lives outside repo)~/.claude/projects/<hash>/CLAUDE.md(personal project notes, lives outside repo)
These are automatically outside your repo, so there's nothing to gitignore.
Q5: How does CLAUDE.md relate to Cursor Rules / Copilot Instructions / Windsurf Rules?
Same concept — project-level instructions for an AI coding assistant. Different tools use different file names and formats:
| Tool | File | Format |
|---|---|---|
| Claude Code | CLAUDE.md | Markdown |
| Cursor | .cursor/rules/ | Markdown |
| GitHub Copilot | .github/copilot-instructions.md | Markdown |
| Windsurf | .windsurfrules | Markdown |
They're not interchangeable (each tool reads its own file), but the content principles are the same. If you use multiple AI tools, you may need to maintain similar files for each — or create a shared source and copy it.
Q6: Can I use CLAUDE.md to make Claude behave differently for different tasks?
Yes, using conditional instructions (see Section 8.1). Claude understands context-dependent rules:
- When writing tests: use `describe`/`it` blocks, include edge cases
- When refactoring: preserve all existing tests, run full suite after changes
- When reviewing code: focus on type safety, error handling, and performance
- When writing documentation: use JSDoc format, include examplesThis is more effective than trying to cover every scenario with unconditional rules.
Q7: How often should I update CLAUDE.md?
Treat it like your linter config — update it when:
- Claude repeatedly makes the same mistake (add a rule)
- You add new tools or change build commands (update commands)
- A rule never seems to matter (remove it)
- Your tech stack changes (update versions)
- New team members report confusion (clarify)
A monthly review is a good cadence. Use /memory for quick additions during conversations, then periodically promote important memories to the project CLAUDE.md.
Q8: Does CLAUDE.md work with Claude on the web (claude.ai)?
No. CLAUDE.md is specific to Claude Code (the CLI/IDE tool). Claude on the web (claude.ai) uses Project Knowledge for similar functionality, but it's a different system. CLAUDE.md files are only read by Claude Code when it starts a session in your project directory.
Summary
CLAUDE.md boils down to three things:
- High-signal content only — Build/test commands, non-obvious conventions, and critical warnings are the highest-value content. Don't write a novel; write a cheat sheet.
- Right level, right content — Use the five-level hierarchy wisely: team conventions in the project root, module-specific rules in subdirectories, personal preferences in user-level, and ephemeral notes in memory.
- Iterate like code — Start small, add rules when Claude makes mistakes, remove rules that don't matter, review changes in PRs. A living CLAUDE.md beats a perfect-on-day-one CLAUDE.md.
Spending 30 minutes on a good CLAUDE.md saves you time in every future conversation. It's probably the highest-ROI file in your entire project.
Recommended Reading
- Claude Code Advanced Guide — The complete getting-started guide for Claude Code
- The Complete settings.json Guide — CLAUDE.md's partner: permissions, hooks, model, and environment config
- Context Management Guide — Manage context effectively to make CLAUDE.md even more powerful
- Claude Code Hooks Guide — Automate formatting, linting, and validation with lifecycle hooks
- Effective Prompt Guide — After configuring your project, writing good prompts is the next step
- Custom Slash Commands Guide — Turn common operations into reusable one-click commands
- MCP Server Deep Dive — Extend Claude Code's capabilities with external tool servers