A good CLAUDE.md is like a great onboarding document: it tells the new team member exactly what they need to know, nothing more. Here is a systematic approach to writing one.
What to include
1. Tech stack summary
Tell Claude what technologies you use and how they fit together.
## Stack
- Runtime: Node.js 20 with TypeScript 5.4
- Framework: Astro 5 with React 18 for interactive components
- Styling: TailwindCSS 3.4 with custom design tokens
- Database: Cloudflare D1 (SQLite) via Drizzle ORM
- Deployment: Cloudflare Pages (frontend) + Workers (API)This prevents Claude from suggesting incompatible libraries or outdated patterns.
2. Commands
List the commands Claude needs to run. This is one of the most valuable sections because Claude can execute these directly.
## Commands
| Command | Purpose |
|---------|---------|
| npm start | Start dev server + API concurrently |
| npm test | Run Vitest test suite |
| npm run lint | ESLint + Prettier check |
| npm run db:migrate | Apply database migrations |
| npm run build | Production build |3. Coding conventions
Be specific. "Write clean code" is useless. "Use named exports, never default exports" is actionable.
## Conventions
- Use functional components with hooks, never class components
- All API responses follow { data, error, meta } envelope format
- File names use kebab-case: user-profile.tsx, not UserProfile.tsx
- Database queries go through the ORM, never write raw SQL
- All user-facing strings must use the i18n translation function t()4. Project structure overview
Help Claude understand where things live.
## Structure
- src/pages/ - Astro page routes (.astro files)
- src/components/ - React components (interactive, use client:load)
- src/services/api.ts - API client, all backend calls go through here
- worker/ - Cloudflare Worker backend (separate from frontend)
- migrations/ - SQL migration files for D15. Do/Don't rules
These are the most powerful lines in your CLAUDE.md. When Claude makes a specific mistake, add a rule to prevent it.
## Rules
- DO: Use Zod for all input validation
- DO: Add error handling to every async function
- DON'T: Use any - always provide explicit TypeScript types
- DON'T: Import from relative paths across module boundaries, use path aliases
- DON'T: Add console.log statements, use the logger utilityWhat to skip
Do not explain technologies Claude already knows
Claude knows what JavaScript is. Claude knows how React hooks work. Claude knows SQLWhat is sql?A language for querying and managing data in relational databases, letting you insert, read, update, and delete rows across tables. syntax. Explaining these basics wastes context tokens.
# BAD - wastes tokens
JavaScript is a programming language that runs in browsers.
React uses a virtual DOM to efficiently update the UI.
# GOOD - project-specific info only
We use React 18 with the new use() hook for data fetching.Do not duplicate your README
Your README explains the project to humans. CLAUDE.md gives Claude actionable instructions. They serve different purposes.
Do not include information that changes frequently
If something changes every week, it will be outdated in your CLAUDE.md more often than it is current. Focus on stable conventions.
Never include secrets
CLAUDE.md is committed to version control. APIWhat is api?A set of rules that lets one program talk to another, usually over the internet, by sending requests and getting responses. keys, database passwords, and tokens do not belong here. Use environment variables and reference them by name.
# BAD
API_KEY=sk-abc123def456
# GOOD
API keys are in .env (not committed). Required vars: API_KEY, DB_URL, REDIS_URLThe feedback loop
The most effective CLAUDE.md files are built iteratively, not written in one sitting. Here is the process:
- Start with the basics. Tech stack, commands, and a few conventions.
- Work with Claude normally. Notice when it makes mistakes or asks questions it should not need to ask.
- Add a rule. Every time Claude gets something wrong, add a specific instruction to CLAUDE.md.
- Test. Start a fresh conversation and verify Claude follows the new rule.
- Repeat. Over days and weeks, your CLAUDE.md becomes increasingly precise.
This iterative approach works because you discover the rules you actually need through real usage, not by guessing upfront.
| CLAUDE.md section | What to write | Example |
|---|---|---|
| Stack | Technologies and versions | "React 18, TypeScript 5.4, Vite, Vitest" |
| Commands | What Claude needs to run | "npm test, run Vitest" |
| Conventions | Specific, actionable rules | "Named exports only, never default" |
| Structure | Where things live | "src/services/, business logic" |
| Do/Don't | Mistake prevention | "DON'T use any, use unknown" |
Testing your CLAUDE.md
The simplest test: start a brand new Claude conversation in your project and give it a task without any extra context. Does it follow your conventions? Does it run the right commands? Does it put files in the right places?
If Claude makes a mistake that your CLAUDE.md should have prevented, either:
- The instruction is missing, add it
- The instruction is vague, make it more specific
- The instruction is buried, move it higher in the file