← All posts

CLAUDE.md: The File That Decides Whether Claude Code Is Good or Bad

Nine out of ten "Claude Code is bad at my codebase" complaints are actually "my CLAUDE.md is bad." Here is how to write one that works.

CLAUDE.md: The File That Decides Whether Claude Code Is Good or Bad

If you have ever thought "Claude Code kind of sucks at this project," I have a theory. You do not have a CLAUDE.md file. Or you have one, but it was written in two minutes and says things like "This is a React app. Please follow best practices."

That file is the single biggest lever you have for making Claude Code go from mediocre to genuinely great on your codebase. And almost nobody writes one well. This post is how.

What CLAUDE.md actually is

CLAUDE.md is a plain markdown file that Claude Code automatically loads into every session when you are working in that project. Global one lives at ~/.claude/CLAUDE.md. Project one lives at the root of your repo. Claude Code reads both and stitches them into the system prompt before your first message.

This means everything you put in CLAUDE.md shapes every response. It is not "additional context" — it is literally the operating manual Claude uses to understand your project.

What most CLAUDE.md files look like
# My Project

This is a Next.js app. Uses TypeScript. Follow best practices.

## Commands

npm run dev — dev server
npm run build — build
npm run test — tests

That is not a CLAUDE.md. That is a README with fewer words. Claude can figure out all of that by reading package.json. You spent zero tokens of your system prompt on information Claude actually needed.

What a good CLAUDE.md looks like

A good CLAUDE.md answers the questions Claude cannot answer by reading the code. Specifically:

1. Things that are invisible in the source

"This codebase was migrated from Vue in 2024 — any file ending in .legacy.ts is pre-migration and should not be modified without checking with the team."

Claude can read .legacy.ts files. Claude cannot read the history of your migration. Tell it.

2. Conventions that have consequences

"Every new component must have a Storybook story. The test runner fails the build if coverage drops."

If you do not say this, Claude writes the component, skips the story, and you find out in CI.

3. Where things live

"Database migrations go in /migrations. Each one is a numbered SQL file: 0023_add_column.sql. Never edit a shipped migration — always create a new one."

Claude is very good at inferring file layout for standard projects. It is very bad at inferring your specific migration convention.

4. Known bad patterns

"Do not use JSON.stringify for logs — we have a custom logger in src/lib/logger.ts that handles redaction. Using the wrong one leaks PII."

This is the single highest-value type of entry. One line prevents entire categories of production incidents.

5. Decision context

"We chose Drizzle over Prisma in 2025 because we needed raw SQL access for the reporting layer. Do not suggest migrating — the decision was deliberate."

Claude is trained on "common best practices." Your project has specific tradeoffs. Name them or Claude will keep suggesting to undo them.

The structure that works

Here is the skeleton I use for every project:

# <Project Name>

<One paragraph: what this project does, who uses it, what stage it is in>

## Quick Start

<Commands a new collaborator would actually run>

## Architecture

<High level — the three or four pieces and how they talk>

## Non-Negotiable Rules

<Numbered list of things that MUST happen or MUST NOT happen>

## Gotchas

<Things that will bite you. Every project has 3-10 of these>

## Where Things Live

<Map of directories — only the ones where the purpose is non-obvious>

## External Systems

<Databases, APIs, services Claude might need to know exist>

That is it. Six sections. Usually 100-300 lines total.

Write it like you are onboarding a senior engineer

The single best framing for CLAUDE.md is "if a senior engineer joined the team today, what would I tell them on day one before they touched the code?"

Not "here is how React works." They know. Not "here are our commands." They can read package.json.

But:

  • "The customer_id field is a string because we support non-numeric IDs from legacy imports."
  • "We use React Query for server state, never Redux — the Redux code you see is being deleted."
  • "Staging auto-deploys from main. Do not push broken code to main even for experiments."

Those are the entries that pay off.

Keep it living

CLAUDE.md is not a one-time write. Every time Claude does something you had to correct — "no, we use Zod here, not Joi" — that is a CLAUDE.md entry you should add. Next time, Claude gets it right the first time.

I treat adding to CLAUDE.md as part of my normal workflow. If I had to explain something twice, it goes in the file. After a month, the file is dense with institutional knowledge and Claude is dramatically more useful.

Two CLAUDE.md files, two jobs
  • Project CLAUDE.md — specific to this codebase. Architecture, rules, gotchas.
  • Global CLAUDE.md (~/.claude/CLAUDE.md) — your personal preferences. "Prefer concise responses." "Do not add trailing summaries." "When explaining code, use file_path:line_number format."

Both get loaded, both apply. Keep them non-overlapping.

The payoff

Every hour you spend sharpening CLAUDE.md saves you 10-50 hours of "no Claude, that is not how we do it here" across the life of the project. It is the highest-leverage investment in your Claude Code workflow, full stop.

If you have been putting this off, close this tab, open your editor, and spend 30 minutes on your CLAUDE.md. You will feel the difference on the next prompt.