How should you set up CLAUDE.md in a monorepo?
Put a short CLAUDE.md at the repository root for rules that apply everywhere, a CLAUDE.md in each package for that package's stack and commands, and cross-cutting rules in .claude/rules/ with a paths field. Claude Code loads the root file at launch and each package's file only when it works in that package, so it gets repository-wide rules plus only the conventions for the code it is touching.
A single root CLAUDE.md breaks down in a monorepo. Anthropic's monorepo guide puts it plainly: one root file tends to either grow to cover every subsystem, costing context on unrelated instructions, or stay too generic to help. Splitting by directory fixes both, and the memory docs recommend keeping each file under 200 lines.
This page gives you three copyable pieces: a root template, two package templates, and path-scoped rules. The example uses pnpm workspaces and Turborepo, labeled as swappable; the same layout works with npm, Yarn or Bun workspaces, Nx, a Cargo workspace or a Go workspace. For the file format in general, see what a CLAUDE.md file is.
How does Claude Code load CLAUDE.md files in a monorepo?
Per the memory docs, Claude Code loads CLAUDE.md and CLAUDE.local.md from your working directory and every directory above it at launch. Files in subdirectories below the working directory load on demand, once Claude reads, writes or edits a file in that subdirectory. All loaded files are concatenated, not overridden, ordered from the root down, so the file closest to where you started is read last.
| You start Claude from | CLAUDE.md loaded at launch | File access |
|---|---|---|
| The repository root | The root file; package files load on demand | Every file |
apps/web/ |
apps/web/CLAUDE.md plus the root file |
That subtree, until you grant more |
Siblings never load each other: a session started in apps/web/ does not read packages/api/CLAUDE.md. Run /context and check the list under Memory files to see exactly what loaded.
The root CLAUDE.md template
Save this as CLAUDE.md at the repository root. It holds only what is true in every package.
@AGENTS.md
# <Repo name>
<One sentence: what this repo contains and who works in it.>
Workspaces: pnpm (pnpm-workspace.yaml). Task runner: Turborepo (turbo.json). Both swappable.
## Layout
- `apps/web/`: <Next.js site>. Has its own CLAUDE.md
- `apps/mobile/`: <Expo app>. Has its own CLAUDE.md
- `packages/ui/`: shared React components. Has its own CLAUDE.md
- `packages/config/`: shared ESLint and TypeScript config
- Each package's CLAUDE.md holds its stack, commands and conventions. Read it before editing there
## Commands (run from the repo root)
- Install: `pnpm install`, only at the root
- Everything: `pnpm build`, `pnpm test`, `pnpm lint` (root scripts call `turbo run`)
- One package: `pnpm turbo run test --filter=@acme/web`
- A package and everything that depends on it: `pnpm turbo run test --filter=...@acme/ui`
- Add a dependency to one package: `pnpm add <dep> --filter @acme/web` (ask first)
- Done means: build, lint and test pass for every package the change touches
## Rules for every package
- Internal packages are linked with `"workspace:*"`. Never point them at a published version
- Change a shared package and its consumers in the same task; do not leave a consumer broken
- Never edit build output (`dist/`, `.next/`, `.turbo/`) or generated files
- Commit subjects start with the package name: `web: add pricing page`
- Do not add a root dependency unless every package needs it
## Gotchas
- Turborepo caches task results. A cached pass on unchanged inputs is expected
- <Your repo's own surprises: services to start, codegen steps, env files per app>
What goes in each package CLAUDE.md?
Each package file holds what is different about that package: its stack, its commands, its folders and its rules. Keep it short and do not repeat the root file, because both load together. For a full single-stack file, start from the Next.js, React Native and Expo, FastAPI, Go or Rust template and trim what the root already says.
Save this as apps/web/CLAUDE.md:
# apps/web: <Next.js marketing site and dashboard>
Stack: Next.js (App Router), TypeScript strict, Tailwind CSS.
Run commands from this folder: `pnpm dev`, `pnpm test`, `pnpm lint`.
- Routes live in `app/`. Shared UI comes from `@acme/ui`; do not copy components here
- Server-only modules import `server-only`. Secrets live in this app's `.env.local`
- Copy `.env.example` to `.env.local` before running anything
- E2E tests need the API running first: <how to start it>
Save this as packages/ui/CLAUDE.md:
# packages/ui: shared React components
Used by apps/web and apps/mobile. A change here can break both.
- Every component is exported from `src/index.ts`
- No app-specific logic, data fetching or environment variables in this package
- Changing a prop is a breaking change: update every consumer in the same task
- Test with `pnpm test` here, then `pnpm turbo run test --filter=...@acme/ui` from the root
How do you add path-scoped rules with .claude/rules?
Some rules cut across packages, like how tests or migrations are written. Put them in the root .claude/rules/ with a paths field, and Claude Code loads each one only when it reads or edits a matching file. Save this as .claude/rules/tests.md:
---
paths:
- "apps/*/src/**/*.test.{ts,tsx}"
- "packages/*/src/**/*.test.{ts,tsx}"
---
# Test rules
- Test behavior through the public API of the module, not private helpers
- No network calls in unit tests; mock at the package boundary
- Every bug fix comes with a test that failed before the fix
Rules can also live inside a package. The memory docs say a project rule's patterns are relative to the directory that contains its .claude folder, so packages/db/.claude/rules/migrations.md with paths: ["migrations/**/*.sql"] matches files under packages/db/migrations/. Rules without a paths field load at launch like CLAUDE.md, so give every package-specific rule a pattern.
What does each part of the layout do?
Root @AGENTS.md import. Turborepo can maintain a managed block in the root AGENTS.md that points agents to the docs bundled with the installed turbo version, according to the Turborepo AI guide. It is opt-in with "agentGuidance": true in the root turbo.json, and new projects from the default starter include it. Because Claude Code skips AGENTS.md once a CLAUDE.md exists, the import keeps that block loaded. Delete the line if you have no AGENTS.md.
Layout and per-package pointers. The root file maps the repo so Claude can find the right package from the root, and tells it each package has its own rules. The nested files carry the details, which matches the two-level split in Anthropic's guide.
Commands. pnpm reads workspace packages only from pnpm-workspace.yaml and links internal packages with the workspace: protocol, per the pnpm workspace docs. Turborepo recommends root scripts that call turbo run and documents --filter in its running tasks guide, where a leading ... adds every package that depends on the one you name. pnpm's own filtering syntax works the same way for pnpm --filter. Telling Claude to test dependents is the single most useful monorepo rule: a shared package change that passes its own tests can still break three apps.
Path-scoped rules. paths is the only frontmatter field Claude Code reads from a rule, and it accepts globs with brace expansion like {ts,tsx}. A rule loads when Claude uses Read, Write or Edit on a matching file, so test rules cost nothing during a CSS change.
Which mistakes does this layout prevent?
| Without it | What prevents it |
|---|---|
| A 600-line root file loads in every session | Root holds only shared rules; package files load on demand |
Claude edits packages/ui and breaks an app it never tested |
"Change a shared package and its consumers in the same task" and the ...@acme/ui filter |
| Claude runs npm commands in a pnpm repo | The "Workspaces: pnpm" line and the command list |
| An internal package is pinned to an old published version | "Never point them at a published version" |
| Frontend rules leak into backend work | Per-package CLAUDE.md files and paths rules |
| Another team's conventions show up in your session | claudeMdExcludes (see below) |
How do you adapt it to your repo?
- Nx instead of Turborepo: replace the commands with
npx nx run-many -t build lint test,npx nx test <project>andnpx nx affected -t test, from the Nx run tasks docs.npx nx configure-ai-agentscan also write CLAUDE.md, AGENTS.md, MCP config and Nx skills for you, per the Nx AI setup page; review its output against this template. - npm, Yarn or Bun workspaces: list the
workspacesfield in the root package.json instead of pnpm-workspace.yaml and use that tool's workspace flag. - Skip other teams' files: add
"claudeMdExcludes": ["**/packages/legacy-*/**"]to.claude/settings.local.jsonfor yourself, or to.claude/settings.jsonfor the team. The monorepo guide notes the list is static, so to focus on one package for a day, start Claude in that package instead. - Work across sibling packages: from
apps/web/, runclaude --add-dir ../../packages/ui. That directory's CLAUDE.md loads only if you also setCLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1, and directories in theadditionalDirectoriessetting never load theirs. - Faster worktrees: the
worktree.sparsePathssetting checks out only the listed directories when Claude creates a worktree. The worktrees guide covers the rest. - Package procedures: put multi-step workflows in
packages/<name>/.claude/skills/instead of CLAUDE.md, so they load only when relevant. See Claude Code skills.
How does AGENTS.md fit into a monorepo?
Several tools now write AGENTS.md files: Turborepo at the root, Next.js inside each app, Expo inside each mobile app, and Nx when you run its setup command. Claude Code's AGENTS.md rules matter more in a monorepo than anywhere else. In the default mode, Claude reads AGENTS.md only when there is no CLAUDE.md or CLAUDE.local.md in the working directory or above it. Once the root has a CLAUDE.md, every AGENTS.md below it is skipped.
You have two clean options. Give each package that has an AGENTS.md its own CLAUDE.md that starts with @AGENTS.md, as the Next.js and Expo templates do. Or type /config and set Project instructions to claude-md-and-agents-md, which loads each directory's CLAUDE.md files first and its AGENTS.md after them, without reading an imported file twice. If the whole team uses several agents, the AGENTS.md guide and the CLAUDE.md vs AGENTS.md comparison cover which file should hold the shared rules.
How do you keep monorepo instructions current?
Anthropic's guide suggests reviewing CLAUDE.md edits in pull requests like any other documentation, letting each directory's owner maintain its file, and revisiting the files after major model releases, when old workarounds become overhead. /doctor prompt-audit (Claude Code v2.1.283 or later) checks CLAUDE.md, AGENTS.md and rules files for outdated or conflicting content and proposes edits. When a rule must never be broken, such as never editing generated code, use a hook, because CLAUDE.md is context, not enforcement. Claude Code memory explains load order in more depth.
If you maintain several monorepos, the root and package templates are worth keeping in one place. Kipt stores prompts and Agent Skills as Markdown in a private GitHub repo you own, so you could save each template as a prompt with blanks like {{scope:@acme}} and fill them per repo.