quiccsite

How to Write a Good CLAUDE.md File (With Examples)

If you're using Claude Code, the single most impactful thing you can do is write a good CLAUDE.md file. It's the first thing Claude reads when it enters your project, and it shapes every decision it makes.

Think of it as onboarding documentation — but for your AI pair programmer.

What is CLAUDE.md?

CLAUDE.md is a markdown file you place at the root of your repository. When Claude Code starts a session, it reads this file to understand your project's conventions, architecture, and preferences. It's not a prompt — it's persistent context.

You can also place CLAUDE.md files in subdirectories for scoped instructions (especially useful in monorepo setups), and a global one at ~/.claude/CLAUDE.md for preferences that apply across all your projects.

The hierarchy

Claude Code reads CLAUDE.md files in order of specificity:

  1. ~/.claude/CLAUDE.md — your global preferences
  2. ./CLAUDE.md — project root instructions
  3. ./src/CLAUDE.md — subdirectory-scoped instructions (only loaded when working in that directory)

More specific files take precedence over general ones.

What to include

Project description (2-3 sentences max)

Tell Claude what this project is and what stack it uses. Don't write a novel.

This is a Next.js 14 app using the App Router, Prisma ORM, and PostgreSQL.
It's a B2B SaaS for inventory management.

Build and test commands

Claude needs to know how to verify its work. Be explicit.

## Commands
- `npm run dev` — start dev server
- `npm test` — run vitest
- `npm run lint` — eslint + prettier check
- `npm run typecheck` — tsc --noEmit

Coding conventions

This is where CLAUDE.md really earns its keep. Be specific about the patterns you use.

## Conventions
- Use named exports, not default exports
- All components use the `function` keyword, not arrow functions
- API routes return `NextResponse.json()`, never raw `Response`
- Database queries go in `src/lib/db/` — never call Prisma directly from routes
- Error handling: let errors bubble up to the global error boundary, don't try-catch in components

What NOT to do

Negative constraints are just as important as positive ones.

## Don't
- Don't add `console.log` — use the `logger` util from `src/lib/logger`
- Don't create new utility files — check `src/lib/` first
- Don't use `any` type — use `unknown` and narrow
- Don't add comments unless the logic is genuinely complex

What NOT to put in CLAUDE.md

A complete example

Real-time collaboration app built with Elixir/Phoenix, LiveView, and PostgreSQL.

## Commands
- `mix phx.server` — start dev server
- `mix test` — run tests
- `mix format --check-formatted` — check formatting
- `mix dialyzer` — type checking

## Conventions
- Contexts (in `lib/app/`) own all database access
- LiveView modules go in `lib/app_web/live/`
- Use changesets for all data mutations, never raw Ecto queries
- All public context functions have @doc and @spec
- Pattern match on function heads, don't use if/else chains

## Don't
- Don't use Ecto.Repo directly outside of context modules
- Don't add JavaScript unless absolutely necessary — prefer LiveView
- Don't create GenServers without discussing the supervision strategy first

Tips

Keep it under 100 lines. If your CLAUDE.md is longer than that, Claude has to process more context on every turn, and the important stuff gets diluted.

Update it when you correct Claude. If you find yourself repeatedly telling Claude the same thing — "don't use default exports", "put queries in the db layer" — add it to CLAUDE.md so you only say it once. You can also use Claude Code's memory system to persist corrections across sessions automatically.

Use subdirectory CLAUDE.md files for monorepos. Put shared conventions in the root file and package-specific rules in each package's own CLAUDE.md.

Test it. Start a fresh Claude Code session and give it a task. If it violates your conventions, your CLAUDE.md isn't clear enough.