One CLAUDE.md at the repo root works fine for a single app. In a monorepo with five packages, three apps, and a shared library, that same file turns into a 600-line dumping ground that Claude reads on every request and half-ignores. The fix is not a bigger file. It is multiple CLAUDE.md files placed where the context actually lives, so each package carries its own rules and the root stays short.

This guide covers where the files go, the order Claude reads them in, what belongs at each level, and how to stop the whole set from drifting out of date the week after you write it.

Key takeaways

  • Claude Code reads CLAUDE.md files hierarchically: the root file plus any file in the directory tree from your working directory up, so a monorepo can have one root file and one per package.
  • Put shared, repo-wide rules at the root. Put package-specific rules (build commands, framework quirks, test runners) in each package's own CLAUDE.md.
  • Keep each file short and scoped. A nested file that repeats the root file wastes tokens and creates conflicts.
  • Use @path/to/file imports to pull in a shared block instead of copy-pasting it into every package.
  • The real failure mode is not structure, it is staleness: the build command changes, the file does not, and Claude confidently runs the old one. Structure once, then keep it current.

---

Why one root CLAUDE.md breaks down in a monorepo

A CLAUDE.md file is instructions Claude Code loads automatically as context. In a single-package repo, one file at the root is correct: your build command, your test runner, your conventions, done.

A monorepo is different because the answer to "how do I run the tests here" depends on which package you are in. The web app uses pnpm test. The Rust core uses cargo test. The docs site has no tests at all. Cram all of that into one root file and three things go wrong: Claude loads rules for packages you are not touching, contradictions pile up with no signal about which applies where, and the file grows past the point where anyone maintains it.

The monorepo answer is to split context by location. The root file holds what is true everywhere. Each package holds what is true only there.

Where Claude.md files load from: the file location and order

This is the part people get wrong, so it is worth being precise. Claude Code discovers CLAUDE.md files in a few places, and the effective context is the combination of them.

CLAUDE.md file location, by scope:

LocationPathScopeCommitted to git
Enterprise / systemOS-level managed pathAll projects on the machineNo (managed)
User global~/.claude/CLAUDE.mdEvery project for that userNo (personal)
Project root<repo>/CLAUDE.mdThe whole repoYes
Subdirectory / package<repo>/packages/api/CLAUDE.mdThat package and belowYes
Local overrideCLAUDE.local.mdPersonal, per-projectNo (gitignored)

The load behavior that matters for a monorepo: Claude reads the root file and then any CLAUDE.md in the directory tree between your current working directory and the root. Start Claude in packages/api/, and it pulls in the root CLAUDE.md plus packages/api/CLAUDE.md. It does not load packages/web/CLAUDE.md, because that file is not on the path from api up to the root.

Files that sit deeper than your working directory are loaded lazily: Claude reads a nested CLAUDE.md when it actually navigates into that subtree, not upfront. So a large monorepo does not pay the token cost of every package's rules on every request. It only loads the ones in play.

Rule of thumb: put a rule at the shallowest location where it is universally true. If it is true everywhere, root. If it is true only inside one package, that package's file.

What goes at the root vs each package

Once you accept that location equals scope, the split writes itself.

Root CLAUDE.md holds repo-wide truth:

  • The package manager and workspace tool (pnpm workspaces, Turborepo, Nx, Cargo workspaces).
  • Cross-cutting conventions: commit message format, branch rules, formatting, the one-line description of what each top-level directory is.
  • How the packages relate: which one is the shared library, which apps depend on it.
  • Global do-nots: "never edit generated files in dist/," "never commit secrets."

Each package CLAUDE.md holds local truth:

  • The exact build, dev, and test commands for that package.
  • Framework-specific quirks (a Next.js app router gotcha, a specific database migration command).
  • What that package is responsible for and what it must not reach into.
  • Local file-structure notes a newcomer would need.

Here is a concrete root file for a typical pnpm monorepo:

# Monorepo root

This is a pnpm workspace. Packages live under `packages/*`, apps under `apps/*`.
- Install: `pnpm install` at the root only.
- `packages/ui` is the shared component library. Apps import from it; it imports from nobody.
- Never edit `packages/*/dist` (build output).
- Commit style: Conventional Commits. Branch off `main`, never push to `main` directly.

Per-package build and test commands live in that package's own CLAUDE.md.

And the matching file inside apps/web/CLAUDE.md:

# apps/web (Next.js 16, app router)

- Dev: `pnpm --filter web dev`
- Test: `pnpm --filter web test` (Vitest)
- E2E: `pnpm --filter web e2e` (Playwright, needs `pnpm --filter web build` first)
- This app imports UI only from `@repo/ui`. Do not copy components in-tree.
- Env vars are validated in `src/env.ts`; add new ones there or the build fails.

Notice the web file says nothing about pnpm workspaces or commit style. That is the root's job. No repetition, no conflict.

Sharing a block without copy-paste: @-imports

Sometimes a chunk of context is shared by several packages but not the whole repo. Three of your five services use the same database and the same migration workflow. You do not want that block in the root (it is not universal), and you do not want it pasted into three files (now you maintain three copies).

Claude Code supports imports. A line like See @../../docs/db-workflow.md for the shared migration steps. inside a CLAUDE.md pulls in another file. Write the shared block once in docs/db-workflow.md, then import it from each service's CLAUDE.md and update it in one place. Imports resolve relative to the file doing the importing and can point at any readable path in the repo. This is the cleanest way to keep "shared but not global" context DRY.

A quick comparison of the three ways to share context:

ApproachMaintenance costBest for
Repeat the block in each package fileHigh (N copies drift apart)Nothing, avoid it
Push it up to the root fileLow, but pollutes unrelated packagesTruly repo-wide rules
@import a shared docLow, single sourceShared-by-several, not-by-all

How to generate a Claude.md file per package fast

You do not have to hand-write every file. To generate a CLAUDE.md file for a package, the fastest path is to run /init from inside that package's directory. Claude Code scans the local files and drafts a starter file with the build commands and conventions it can infer. Then you trim it: delete anything the root already covers, tighten the commands, and remove guesses that are wrong.

A few rules keep generated files useful instead of bloated:

  • Cut duplication with the root immediately. A generated per-package file often re-states the package manager.
  • Keep it under roughly 40 to 60 lines. If it is longer, it is documentation that belongs in a real doc, imported with @.
  • Write commands you have actually run. A wrong test command is worse than no command, because Claude will trust it.

Getting the structure right on day one is the easy half. The hard half is what happens next.

The real problem is not structure, it is staleness

Here is the failure that actually bites teams, and no folder layout prevents it. You set up clean, per-package CLAUDE.md files. Two months later the web app moves from Vitest to a different runner, a service renames its migration command, and the shared UI library changes its import path. Nobody updates the CLAUDE.md files, because updating five scattered instruction files is not part of anyone's job.

Now Claude reads confident, specific, and wrong instructions. It runs the old test command. It imports from the old path. Precise-but-stale context is more dangerous than vague context, because the model has no reason to doubt it.

This is the same trap every static setup file hits. It was accurate the day you wrote it and it decays from there, and the maintenance burden scales with how many files you have. A well-structured monorepo makes this worse, not better, because now there are more files to keep honest.

The durable fix is to stop treating your AI's context as files you edit by hand and start treating it as something that maintains itself from what you already do. That is the idea behind a second brain for your AI that keeps itself current: instead of hand-editing instructions every time a command or a decision changes, the context updates from your real work. Locul distills what you produce into memories with a confidence score, and when a fact changes, the old one is marked superseded and the new one takes over, with history preserved. Your AI works from what is true now, not what was true when you last remembered to edit a file, and everything stays local on your machine by default.

For the part of your setup that genuinely is project structure, CLAUDE.md files are the right tool. For the part that is you, your decisions, and your evolving conventions, a set of files you must remember to update is exactly the thing that goes stale. The two work together: static files for repo layout, a living memory for the context that changes underneath them. For the deeper version of why static context rots, see how to give your AI a memory that lasts, and for how current context bundles differ from frozen prompt files, see what a Memory Pack is.

---

FAQ

How many CLAUDE.md files should a monorepo have?

One at the root, plus one per package or app that has its own build, test, or convention rules. Do not add a CLAUDE.md to a directory that has nothing package-specific to say. The goal is scoped context, not a file in every folder. Shared-by-several blocks live in a doc and get pulled in with an @import rather than becoming their own scattered files.

Where should the CLAUDE.md file be located?

The root CLAUDE.md goes at the repository root, next to your workspace config. Package-specific files go at the root of each package (for example packages/api/CLAUDE.md). Claude Code loads the root file and any CLAUDE.md on the path from your working directory up to the root, and lazily loads deeper ones when it enters those subtrees. Personal, uncommitted notes go in CLAUDE.local.md, which you gitignore.

In what order does Claude read multiple CLAUDE.md files?

It combines them by scope: enterprise or system managed files, then your user-global ~/.claude/CLAUDE.md, then the project root, then any nested package files on your current path, with more local files layering on top of broader ones. More specific, closer-to-your-working-directory instructions take precedence when there is overlap, which is why per-package commands should live in the package file.

How do I generate a CLAUDE.md file automatically?

Run /init in Claude Code from the directory you want the file for. It scans the local project and drafts a starter file with inferred commands and conventions. Treat the output as a draft: cut anything the root file already covers, fix any commands it guessed wrong, and keep it short. Re-running /init later to refresh a draft is fine.

Can nested CLAUDE.md files override the root file?

They do not literally overwrite it, they layer on top of it. When a package file and the root file both speak to the same thing, the more specific package file is what applies inside that package. This is exactly why the split works: put the general rule at the root and the exception in the package, and the exception wins where it lives without you having to restate the general rule.

Why do my CLAUDE.md files keep going out of date?

Because they are static files that only change when a human remembers to edit them, and commands, paths, and conventions change faster than anyone updates docs. Structure reduces clutter but not drift. To keep the context that describes you and your evolving decisions current without hand-editing, pair your CLAUDE.md files with a living memory that updates from your real work, as covered in how to give your AI a memory that lasts.

---

If your CLAUDE.md files are clean but still describe last quarter's setup, the structure was never the problem. The context that changes fastest is the context about you and your decisions, and that is the part no folder layout keeps honest. Locul is a second brain that builds itself from what you already do and keeps itself current, then serves it to your AI over MCP, local-first by default. It is free to start with 500 memories and local AI, no credit card. You can see the difference between a static instruction file and a living one at the download page.

FAQ

Common questions

How many CLAUDE.md files should a monorepo have?

One at the root, plus one per package or app that has its own build, test, or convention rules. Do not add a CLAUDE.md to a directory that has nothing package-specific to say. The goal is scoped context, not a file in every folder. Shared-by-several blocks live in a doc and get pulled in with an @import rather than becoming their own scattered files.

Where should the CLAUDE.md file be located?

The root CLAUDE.md goes at the repository root, next to your workspace config. Package-specific files go at the root of each package (for example packages/api/CLAUDE.md). Claude Code loads the root file and any CLAUDE.md on the path from your working directory up to the root, and lazily loads deeper ones when it enters those subtrees. Personal, uncommitted notes go in CLAUDE.local.md, which you gitignore.

In what order does Claude read multiple CLAUDE.md files?

It combines them by scope: enterprise or system managed files, then your user-global ~/.claude/CLAUDE.md, then the project root, then any nested package files on your current path, with more local files layering on top of broader ones. More specific, closer-to-your-working-directory instructions take precedence when there is overlap, which is why per-package commands should live in the package file.

How do I generate a CLAUDE.md file automatically?

Run /init in Claude Code from the directory you want the file for. It scans the local project and drafts a starter file with inferred commands and conventions. Treat the output as a draft: cut anything the root file already covers, fix any commands it guessed wrong, and keep it short. Re-running /init later to refresh a draft is fine.

Can nested CLAUDE.md files override the root file?

They do not literally overwrite it, they layer on top of it. When a package file and the root file both speak to the same thing, the more specific package file is what applies inside that package. This is exactly why the split works: put the general rule at the root and the exception in the package, and the exception wins where it lives without you having to restate the general rule.

Why do my CLAUDE.md files keep going out of date?

Because they are static files that only change when a human remembers to edit them, and commands, paths, and conventions change faster than anyone updates docs. Structure reduces clutter but not drift. To keep the context that describes you and your evolving decisions current without hand-editing, pair your CLAUDE.md files with a living memory that updates from your real work, as covered in how to give your AI a memory that lasts. --- If your CLAUDE.md files are clean but still describe last quarter's setup, the structure was never the problem. The context that changes fastest is the context about you and your decisions, and that is the part no folder layout keeps honest. Locul is a second brain that builds itself from what you already do and keeps itself current, then serves it to your AI over MCP, local-first by default. It is free to start with 500 memories and local AI, no credit card. You can see the difference between a static instruction file and a living one at the download page.