Prelude
Consider a monorepo with fourteen packages. A React frontend, a Node.js API, a shared TypeScript library, a CLI tool, three microservices in Go, infrastructure-as-code in Terraform, and a handful of utility packages that glue everything together.
Each package has its own build system, its own testing patterns, its own conventions. The initial approach is often a single CLAUDE.md file in the root directory. Enormous. Over four hundred lines of instructions covering every package, every build command, every coding convention.
It works, technically. Claude Code reads it and follows the instructions. But it is slow to load, eats a significant chunk of the context window, and most of the information is irrelevant to whatever happens to be the focus at any given moment.
Claude Code does not just read one CLAUDE.md file. It walks the directory tree. It reads a root-level file for shared context and subdirectory files for package-specific context. It supports a .claude/rules/ directory for glob-scoped rules. It even has a local variant, CLAUDE.local.md, for personal preferences that should not be committed to version control.
Once this hierarchy is understood, the entire CLAUDE.md setup can be restructured. The root file drops to sixty lines of shared conventions. Each package gets its own focused file. Rules handle file-type-specific behaviour. The result is faster sessions, more relevant context, and Claude Code that behaves appropriately no matter which part of the monorepo is being worked on.
This guide is the complete playbook for structuring CLAUDE.md files in a monorepo. If you have more than a few packages in a single repository, this will save you weeks of trial and error.
The Problem
Monorepos are complicated. They contain multiple packages with different languages, different build tools, different testing approaches, and different coding conventions. A React component library has different rules than a Go microservice. A Terraform module has different expectations than a Node.js API.
Claude Code needs to understand these differences. When you ask it to write a test in your React package, it should know to use Jest and React Testing Library. When you ask it to write a test in your Go service, it should know to use the standard testing package with table-driven tests. When you ask it to modify your Terraform configuration, it should know your naming conventions and state backend setup.
A single CLAUDE.md file cannot handle this well. If you put everything in one file, most of the content is noise for any given task. Claude Code loads the entire file into its context window at session start, which means hundreds of lines about your Go microservices are consuming context tokens while you are working on your React frontend. Worse, conflicting instructions from different packages can confuse the model. "Always use semicolons" for your JavaScript and "never use semicolons" for your Go tests are both valid rules, but they conflict when they appear in the same file without clear scoping.
The other extreme, having no CLAUDE.md at all and relying on Claude Code to infer conventions from the code, also fails. Claude Code is good at reading code, but it cannot infer your team's preferences about error handling patterns, commit message formats, or which testing framework to use when multiple options are available. Some things need to be stated explicitly.
The solution is a structured hierarchy of CLAUDE.md files that gives Claude Code the right context at the right time, without wasting tokens on irrelevant information.
The Journey
Understanding the Loading Order
Before you can structure your CLAUDE.md files effectively, you need to understand how Claude Code discovers and loads them. The loading order determines which instructions Claude sees and when.
Claude Code reads CLAUDE.md files from multiple locations, in this order.
First, the user-level file at ~/.claude/CLAUDE.md. This contains personal preferences that apply to every project. Things like "I prefer British English in comments" or "always explain your reasoning before showing code." This file is not part of your repository and is not shared with your team.
Second, the root CLAUDE.md in your project directory. This is the file that sits next to your package.json, go.mod, or whatever defines the root of your monorepo. Claude Code always reads this file, regardless of which subdirectory you are working in.
Third, ancestor directory CLAUDE.md files. Claude Code walks up the directory tree from your current working directory to the project root, reading any CLAUDE.md files it finds along the way. If you start Claude Code in packages/api/, it reads CLAUDE.md files from packages/api/, packages/, and the project root. Subdirectory CLAUDE.md files below your current location load on demand when Claude reads files in those directories, not eagerly at session start.
Fourth, .claude/rules/ files. These are glob-scoped rule files that activate based on the file paths Claude Code is working with. More on these in a later section.
The key insight is that all of these files are additive. Claude Code concatenates them into a single context. It does not replace or override. This means your root file and subdirectory files should complement each other, not repeat each other.
| Level | Location | Loaded when | Scope | What belongs here |
|---|---|---|---|---|
| User | ~/.claude/CLAUDE.md |
Every session, every project | Personal, machine-wide | Response style, language preference, editor shortcuts |
| Project root | <repo>/CLAUDE.md |
Every session in the repo | Team-wide, all packages | Shared conventions, repo map, top-level commands |
| Ancestor | <repo>/packages/<pkg>/CLAUDE.md |
Session started inside the package, or when Claude reads files under it | Single package | Build and test commands, tech stack, package-specific standards |
| Glob-scoped | <repo>/.claude/rules/*.md |
Auto-activated when a matched file is edited | File-type, cross-package | Test conventions, infra-as-code standards, migration rules |
| Local | <repo>/CLAUDE.local.md (gitignored) |
Every session for the developer who created it | Personal, project-specific | Personal overrides that should not ship to the team |
Data source: Claude Code memory documentation, as of 2026-04.
All five levels are additive, not overriding. When the context loaded by two levels disagrees, Claude Code sees both instructions and reconciles them from proximity and specificity, not from an explicit precedence rule. That is why the Anti-Patterns section below warns against contradictory instructions at different levels without clearly signalling the override.
The Root CLAUDE.md for Shared Conventions
Your root CLAUDE.md file is the one every Claude Code session reads, regardless of where in the monorepo the developer is working. This makes it valuable real estate. Every line in this file consumes context tokens for every session. Keep it lean and universal.
Here is what belongs in a root CLAUDE.md for a monorepo.
# MyCompany Monorepo
## Repository Structure
- `packages/web/` - React frontend (TypeScript, Vite)
- `packages/api/` - Node.js API (TypeScript, Express)
- `packages/shared/` - Shared TypeScript library
- `services/auth/` - Authentication service (Go)
- `services/billing/` - Billing service (Go)
- `infra/` - Terraform infrastructure
## Shared Conventions
- Branch naming: `feature/TICKET-123-short-description`
- Commit messages: [conventional commits](https://www.conventionalcommits.org/) (feat:, fix:, chore:, docs:)
- All code must pass CI before merging. Run `make check` to verify locally.
- Never commit secrets. Use environment variables from `.env.local` (gitignored).
- British English in all documentation and comments.
## Monorepo Commands
- `make build` - Build all packages
- `make test` - Run all tests
- `make lint` - Lint all packages
- `make check` - Run build, test, and lint
## Package-Specific Instructions
Each package has its own CLAUDE.md with build commands and conventions.
Check the CLAUDE.md in the package directory before making changes.
Notice what is not in this file. There are no package-specific build commands, no language-specific coding standards, no testing framework details. Those belong in the subdirectory files. The root file provides the map. The subdirectory files provide the territory.
Aim for under a hundred lines in the root file. If you are going over that, you are probably including package-specific details that should live closer to the code they describe.
Package-Level CLAUDE.md Files
Each package in your monorepo should have its own CLAUDE.md file with instructions specific to that package. This is where you get detailed and specific.
Here is an example for a React frontend package.
# Web Frontend
## Build and Test
- Dev server: `npm run dev` (from this directory)
- Build: `npm run build`
- Test: `npm test`
- Test single file: `npm test -- path/to/test.ts`
- Lint: `npm run lint`
- Type check: `npx tsc --noEmit`
## Tech Stack
- React 19 with TypeScript
- Vite for bundling
- Tailwind CSS for styling
- React Query for server state
- Zustand for client state
- Jest + React Testing Library for tests
## Coding Standards
- Functional components only. No class components.
- Use named exports. No default exports.
- Co-locate tests with source files: `Button.tsx` and `Button.test.tsx` in the same directory.
- Use `interface` for component props, not `type`.
- All components must have a corresponding test file.
- Prefer composition over complex props. Break large components into smaller ones.
## Directory Structure
- `src/components/` - Reusable UI components
- `src/pages/` - Page-level components (one per route)
- `src/hooks/` - Custom React hooks
- `src/api/` - API client and query definitions
- `src/store/` - Zustand store definitions
- `src/types/` - Shared TypeScript types
And here is an example for a Go microservice.
# Auth Service
## Build and Test
- Build: `go build ./...`
- Test: `go test ./...`
- Test with coverage: `go test -coverprofile=coverage.out ./...`
- Run locally: `go run cmd/auth/main.go`
- Lint: `golangci-lint run`
## Coding Standards
- [Standard Go project layout](https://go.dev/doc/modules/layout). cmd/ for entry points, internal/ for private packages.
- Table-driven tests for all functions with multiple input/output combinations.
- Error wrapping with `fmt.Errorf("context: %w", err)`.
- No global state. Pass dependencies through function parameters or struct fields.
- Context propagation through all function chains. First parameter is always `ctx context.Context`.
- Use `slog` for structured logging. No `fmt.Println` in production code.
## Database
- PostgreSQL with `pgx` driver.
- Migrations in `migrations/` directory, numbered sequentially.
- Never modify existing migrations. Always create new ones.
## API
- gRPC with Protocol Buffers. Proto files in `proto/` directory.
- Run `buf generate` after modifying proto files.
- All RPC methods must have request validation.
Each package file is self-contained. A developer working in the Go auth service does not need to know about React Testing Library, and vice versa. Claude Code loads only the relevant files based on where the developer is working.
The .claude/rules/ Directory for Glob-Scoped Rules
Sometimes you need rules that apply to specific file types rather than specific directories. That is where .claude/rules/ comes in. This directory sits in your project root, and each file in it contains a glob pattern in its frontmatter that determines which files the rules apply to.
Here is an example. Create a file at .claude/rules/typescript-tests.md.
---
paths: ["*.test.ts", "*.test.tsx", "*.spec.ts", "*.spec.tsx"]
---
When writing or modifying TypeScript tests, follow these rules.
- Use `describe` and `it` blocks, not `test` blocks.
- Each `describe` block should correspond to a function or component being tested.
- Use `beforeEach` for shared setup. Avoid `beforeAll` unless the setup is genuinely expensive.
- Mock external dependencies. Never make real API calls or database queries in tests.
- Use `jest.fn()` for function mocks and `jest.spyOn()` for method mocks.
- Assert specific values, not just truthiness. Use `toEqual` over `toBeTruthy`.
- Include at least one test for the happy path, one for error handling, and one for edge cases.
And another for Terraform files at .claude/rules/terraform.md.
---
paths: ["*.tf", "*.tfvars"]
---
When working with Terraform files, follow these rules.
- Use `terraform fmt` style. Two-space indentation.
- All resources must have a `tags` block with at least `Environment` and `ManagedBy` tags.
- Use data sources to reference existing resources. Never hardcode ARNs or IDs.
- Variables must have `description` and `type` fields. Include `default` only if the variable is optional.
- Outputs must have `description` fields.
- Use modules for repeated patterns. Never copy-paste resource blocks.
The glob patterns support standard glob syntax. *.rs matches all Rust files. packages/web/**/*.tsx matches all TSX files in the web package. **/migrations/*.sql matches SQL migration files anywhere in the repository.
Rules files are powerful because they activate automatically based on context. When Claude Code edits a test file, it gets the testing rules. When it edits a Terraform file, it gets the infrastructure rules. No manual switching required.
A practical limit is three to five rules files covering the file types with genuinely distinct conventions in your codebase. More than that and you risk overloading the context. The goal is to capture the rules that developers frequently forget or that Claude Code gets wrong without explicit guidance.
CLAUDE.local.md for Personal Preferences
Every developer has preferences that are personal, not organisational. Maybe one developer likes verbose explanations while another prefers terse responses. Maybe one developer wants Claude Code to always suggest tests while another only wants tests when asked.
CLAUDE.local.md is the answer. This file sits in the project root alongside CLAUDE.md, but it is gitignored. Each developer can create their own version with personal preferences that do not affect the team.
# My Preferences
- When explaining code, be concise. Skip the preamble.
- I prefer to see the full file after edits, not just the diff.
- When I ask for a refactor, suggest tests for the refactored code.
- I use vim keybindings, so do not suggest VS Code shortcuts.
Add CLAUDE.local.md to your .gitignore file at the root of the monorepo. This ensures personal preferences stay personal. The system prompts vs CLAUDE.md guide explains the broader distinction between shared configuration and personal preferences in more detail. Teams maintaining a shared prompt library across monorepo packages should also review our Claude system prompt library for patterns that scale.
The Line-Length Guideline
Claude Code loads CLAUDE.md files in full regardless of length. There is no truncation. However, shorter files produce better adherence because they keep the most important instructions prominent in the context window.
The current recommendation is to target under five hundred lines per CLAUDE.md file. This is a best-practice guideline, not a technical limit. If you cannot fit your package's instructions in that range, you are probably including details that do not need to be in the CLAUDE.md at all.
Here is how to prioritise content when approaching the limit.
First priority is build and test commands. These are the instructions Claude Code uses most frequently. Every CLAUDE.md should start with how to build, test, and lint the code.
Second priority is coding standards that Claude frequently gets wrong. If Claude Code consistently uses the wrong import style or the wrong error handling pattern, add a rule for it. If it already follows the convention correctly from reading your code, you do not need a rule.
Third priority is project structure. A brief description of where things live helps Claude Code navigate large packages without reading every directory.
Lowest priority is explanatory text. Claude Code does not need paragraphs explaining why you chose a particular framework. It needs concise instructions about how to use it.
If you genuinely need more context for a particular area, use the @path/to/file syntax to reference external files.
Using Imports to Reference Other Files
Sometimes you need Claude Code to understand detailed specifications, API schemas, or architectural decisions that do not fit neatly in a single CLAUDE.md. The @path/to/file syntax lets you reference other files that Claude Code will load when needed.
# My Package
## Build
- `npm run build`
- `npm test`
## API Schema
@docs/api-schema.md
## Architecture Decisions
@docs/architecture-decisions.md
The @path syntax tells Claude Code to read the referenced file and include its contents in the context. This is more flexible than cramming everything into one file because the imported files can be longer, can be shared across multiple CLAUDE.md files, and can be maintained independently.
Imports work well for three types of content. API documentation that Claude Code needs to generate correct client calls. Architecture decision records that explain why certain patterns are used. And coding standards documents that are maintained by the team and would be duplicated if copied into every CLAUDE.md file.
Be selective with imports. Each imported file adds to the context window size. If you import five large files, you will eat into the context available for your actual conversation with Claude Code.
Mapping CLAUDE.md to Your Monorepo Tool
Different monorepo tools surface packages in slightly different ways, and the CLAUDE.md layout should follow whatever convention the tool already uses so developers are not running cd into directories that do not exist. The table below maps the four most common monorepo tools to a CLAUDE.md placement strategy that fits the tool's own vocabulary.
| Tool | Package location convention | Root CLAUDE.md covers | Package CLAUDE.md sits at | Rules file candidates |
|---|---|---|---|---|
| pnpm workspaces | Paths listed in pnpm-workspace.yaml (commonly packages/*, apps/*) |
Top-level scripts, shared deps, pnpm -r commands, commit style |
Each entry matched by the workspace glob | Test runner rules, shared lint config notes |
| Yarn workspaces | workspaces array in root package.json |
Hoisting policy, yarn workspaces run commands, version-constraint policy |
Each workspace package directory | Test rules, build-artifact policy |
| Nx | apps/ and libs/ with project.json per project |
nx targets, generator conventions, affected-build commands |
Each apps/<name>/ and libs/<name>/ |
Executor/generator rules scoped via paths: ["libs/**/*.ts"] |
| Turborepo | apps/ and packages/ with turbo.json pipeline |
Pipeline names, remote-cache policy, filter syntax (turbo run build --filter=...) |
Each app or package directory | Build-cache hygiene, per-pipeline conventions |
| Bazel | BUILD / BUILD.bazel files alongside sources |
Workspace rules, bazel test //... commands, target naming |
Each directory with a BUILD file, especially language boundaries |
Starlark style rules, visibility policy |
Data sources: pnpm workspaces, Yarn workspaces, Nx mental model, Turborepo docs, Bazel concepts, as of 2026-04.
The rule of thumb is simple. Wherever the monorepo tool expects a configuration file for a package (project.json, package.json, BUILD), drop the package-level CLAUDE.md next to it. That way the CLAUDE.md directory tree matches the tool's directory tree, which is the tree developers already navigate.
A Real-World Monorepo Example
Here is the complete CLAUDE.md structure of a real-world monorepo. The repository has this layout.
myproject/
CLAUDE.md # Root, shared conventions
CLAUDE.local.md # Personal prefs (gitignored)
.claude/
rules/
typescript-tests.md # Rules for *.test.ts files
go-tests.md # Rules for *_test.go files
terraform.md # Rules for *.tf files
packages/
web/
CLAUDE.md # React frontend instructions
api/
CLAUDE.md # Node.js API instructions
shared/
CLAUDE.md # Shared library instructions
services/
auth/
CLAUDE.md # Go auth service instructions
billing/
CLAUDE.md # Go billing service instructions
infra/
CLAUDE.md # Terraform instructions
When a developer opens Claude Code in packages/web/, it loads four sources. The user-level ~/.claude/CLAUDE.md (personal, global), the root CLAUDE.md (shared conventions), the packages/web/CLAUDE.md (React-specific instructions), and any .claude/rules/ files that match the file types being edited.
When the same developer switches to services/auth/, the loaded context changes. The root file stays the same, but packages/web/CLAUDE.md drops out and services/auth/CLAUDE.md loads instead. If they are editing a _test.go file, the go-tests.md rules file also activates.
This is the key benefit of the hierarchy. The context adapts automatically to where the developer is working. No manual switching, no remembering to update settings, no wasted tokens on irrelevant instructions.
Anti-Patterns to Avoid
Teams make the same mistakes repeatedly when setting up CLAUDE.md for monorepos. Here are the patterns to avoid.
Duplicating information across files. If your root CLAUDE.md says "use conventional commits" and every package file also says "use conventional commits," you are wasting context tokens on repetition. Put shared rules in the root file. Put package-specific rules in package files. Never repeat yourself.
Putting everything in the root file. This is the most common mistake. The root file should be a map, not an encyclopedia. If it contains build commands for every package, coding standards for every language, and testing patterns for every framework, it is doing too much. Move package-specific content to package-level files.
Ignoring subdirectory files entirely. Some teams create a single root CLAUDE.md and never add package-level files. This forces the root file to grow indefinitely and means Claude Code gets the same context regardless of where the developer is working. Take advantage of the hierarchy.
Contradicting instructions across levels. If the root file says "always add JSDoc comments" and a package file says "no comments, the code should be self-documenting," Claude Code will receive conflicting instructions. Resolve conflicts by being specific. The root file should set defaults. Package files should override only when necessary, with clear language like "In this package, unlike the general convention..."
Using CLAUDE.md for documentation. CLAUDE.md is for instructions, not documentation. Do not explain the history of your architecture decisions, the rationale behind your tech stack, or the goals of your product. Claude Code does not need this context to write good code. Keep it focused on actionable instructions.
Skills vs CLAUDE.md
Claude Code supports slash commands and skills that provide on-demand context rather than persistent context. Understanding when to use each is important for keeping your CLAUDE.md files lean.
CLAUDE.md is for instructions that should always be active. Coding standards, build commands, project structure. These are things Claude Code needs to know for every interaction within a given scope.
Skills and slash commands are for instructions that are needed occasionally. A complex deployment process, a database migration workflow, a performance profiling procedure. These are detailed instructions that would waste context if loaded into every session but are invaluable when needed.
In a monorepo, use CLAUDE.md for the day-to-day context and skills for specialised workflows. A packages/web/CLAUDE.md tells Claude Code how to build and test the frontend. A /deploy-web skill tells it how to deploy the frontend, including the twelve-step process with environment checks, build verification, CDN invalidation, and smoke tests.
The rule of thumb is simple. If Claude Code needs this information in more than half of the sessions where it is working in a particular scope, put it in CLAUDE.md. If it needs it less frequently, make it a skill or document it in a file that can be imported on demand.
Memory Auto-Save and Project-Specific Memory
Claude Code has a memory feature that automatically saves context to ~/.claude/projects/{project-path}/memory/. This is separate from CLAUDE.md and serves a different purpose.
Memory captures things Claude Code learns during sessions. If you tell it "in this project, we use pnpm, not npm" during a conversation, it may save that to memory so it remembers in future sessions. This is useful for capturing ad-hoc preferences that do not warrant a CLAUDE.md update.
In a monorepo context, memory is project-level, not package-level. This means a correction you make while working in packages/web/ is remembered when you are working in services/auth/. For most corrections, this is fine. But if you make a package-specific correction that should not apply elsewhere, add it to the package-level CLAUDE.md instead of relying on memory.
Periodically reviewing project memory files and promoting useful entries to the appropriate CLAUDE.md file is a good practice. This keeps the important instructions in version control where the whole team benefits from them, rather than locked in a personal memory store.
Troubleshooting Common CLAUDE.md Issues
Teams run into the same problems when setting up CLAUDE.md hierarchies. These are the issues that cause the most confusion, along with the fixes.
Subdirectory File Not Loading
The most common complaint is "I added a CLAUDE.md in my package directory but Claude Code is not following it." This happens when Claude Code is launched from the project root rather than the package directory.
Claude Code loads ancestor CLAUDE.md files (from your current directory up to the root), not descendant files. If you open Claude Code in the project root and ask it to edit a file in packages/api/, it reads the root CLAUDE.md but does not automatically load packages/api/CLAUDE.md at session start. The subdirectory file loads on demand when Claude reads or edits files in that directory.
The fix is to start Claude Code from the package directory when doing focused work on that package.
# This loads both root CLAUDE.md and packages/api/CLAUDE.md
cd packages/api && claude
# This only loads root CLAUDE.md at startup
cd /repo-root && claude
If you need to work across multiple packages in one session, the subdirectory files load as Claude accesses files in those directories. You can also reference a package's CLAUDE.md explicitly in your prompt: "Read packages/api/CLAUDE.md before making changes."
Rules Not Activating for a File Type
If your .claude/rules/typescript-tests.md file is not being applied when you edit test files, check the paths frontmatter. The glob patterns must match the file paths relative to the project root.
---
# Wrong: this matches files named literally "*.test.ts" in the root
paths: ["*.test.ts"]
---
---
# Correct: this matches any .test.ts file anywhere in the repo
paths: ["**/*.test.ts"]
---
The ** prefix is important. Without it, the pattern only matches files in the directory where the rules file lives. With it, the pattern matches recursively through all subdirectories.
Conflicting Instructions Between Levels
When the root file says one thing and a package file says another, Claude Code sees both instructions and has to reconcile them. It does not have a formal override mechanism. Both instructions appear in its context as equally valid.
The solution is to write package-level overrides explicitly. Do not just state the different rule. State that it overrides the root convention.
## Coding Standards
Unlike the project-wide convention of using named exports,
this package uses default exports for React components
because the component library's documentation tooling requires them.
The phrase "unlike the project-wide convention" signals to Claude Code that this is an intentional override, not a conflicting instruction.
Context Window Usage Growing Over Time
As your monorepo grows and you add more CLAUDE.md files and rules, the combined context consumption increases. You can audit this by concatenating all the files Claude would load for a given directory and counting the tokens.
# Rough token estimate (1 token ≈ 4 characters)
cat CLAUDE.md packages/web/CLAUDE.md .claude/rules/*.md | wc -c | awk '{print $1/4 " estimated tokens"}'
If the total exceeds 5,000 tokens, audit each file for content that is redundant, outdated, or better placed in a referenced document using @path imports.
Team Members Overwriting Each Other's CLAUDE.local.md
CLAUDE.local.md should be in .gitignore, but teams sometimes forget to add it during initial setup. If one developer commits their CLAUDE.local.md, it overwrites everyone else's personal preferences on the next pull.
Add this to your root .gitignore before anyone creates the file.
CLAUDE.local.md
If someone has already committed it, remove it from tracking without deleting the local copy.
git rm --cached CLAUDE.local.md
echo "CLAUDE.local.md" >> .gitignore
git add .gitignore
git commit -m "chore: stop tracking CLAUDE.local.md"
Advanced Patterns
Conditional Configuration with Environment Markers
Some teams need different CLAUDE.md behaviour depending on the environment. A developer working on the staging deployment needs different database connection instructions than one working locally.
Since CLAUDE.md does not support conditionals, the practical approach is to use comments that Claude Code can interpret contextually.
## Database Commands
Local development: `npm run db:migrate:local`
Staging: `npm run db:migrate:staging` (requires VPN)
Production: NEVER run migrations from a developer machine.
Claude Code reads natural language. If a developer mentions they are working on staging, Claude will use the staging instructions. This is less precise than conditional logic but works well in practice.
Team-Specific Overrides with Rules Files
Large teams sometimes need different rules for different roles. Frontend developers should not modify backend migration files. Infrastructure engineers should not touch component CSS.
Rather than enforcing this in CLAUDE.md (which cannot restrict access), use .claude/rules/ files to add contextual warnings.
---
paths: ["**/migrations/*.sql"]
---
CAUTION: Database migration files. Only modify if you are the on-call DBA
or have explicit approval. Incorrect migrations can cause data loss.
Always create a new migration file. Never modify existing ones.
This does not prevent Claude Code from editing the file, but it ensures Claude is aware of the sensitivity and communicates the risk to the developer before making changes.
The Lesson
The most valuable lesson from structuring CLAUDE.md files across a monorepo is that context management is a design problem, not a documentation problem. You are not writing documentation for Claude Code to read. You are designing a context system that delivers the right information at the right time with minimal waste.
The hierarchy, with root files for shared conventions, package files for specific instructions, rules for file-type behaviours, and local files for personal preferences, gives you a framework for thinking about where each piece of context belongs. When you add a new instruction, ask yourself three questions. Does every session need this? Does only this package need this? Does only this file type need this?
The answer tells you where it goes. Keep files short. Be specific. Do not repeat yourself. Let the hierarchy do the work of scoping context to the right sessions. Review your CLAUDE.md files regularly, because your conventions evolve and your context should evolve with them.
Conclusion
Structuring CLAUDE.md for a monorepo is straightforward once you understand the loading hierarchy. Put shared conventions in the root file. Put package-specific instructions in subdirectory files. Use .claude/rules/ for path-scoped file-type rules. Keep personal preferences in CLAUDE.local.md.
Target under five hundred lines per file, and use @path/to/file imports for content that does not fit. The payoff is significant. Claude Code behaves consistently across your entire monorepo, loading only the context relevant to the current task. Developers do not need to manually switch modes or remind Claude Code which package they are working in.
For a deeper understanding of the relationship between CLAUDE.md and system prompts, read the system prompts vs CLAUDE.md guide. Anthropic's Claude Code best practices documentation covers the official guidelines that complement the monorepo-specific patterns in this guide. And for practical tips on integrating Claude Code into your daily development routine across any project structure, the Claude Code daily workflows guide covers the workflows and habits that make the biggest difference.
The monorepo adds complexity, but with the right CLAUDE.md structure, Claude Code handles that complexity gracefully. Set up the hierarchy once, maintain it as your codebase evolves, and let Claude Code focus on what it does best: writing good code in the right context.