How Do I Keep Claude Code Lean in a Large Monorepo?

The first time you run Claude Code on a real monorepo, the context usage chart looks like a Black Friday traffic graph. A single "explain how this feature works" question pulls in 40 files, and you're staring at a 150k-token conversation before Claude has typed a word. Here's how to keep Claude Code useful on a huge codebase without eating through your token budget — or your patience.
Why this matters
Claude Code is a great collaborator on small projects and a great collaborator on big projects if you configure it correctly. Out of the box, it defaults to reading liberally: the file you referenced, its imports, related test files, CLAUDE.md, and whatever else it thinks relevant. That's the right default on a 50-file project and the wrong default on a 50,000-file monorepo.
With the right configuration — scoped attention, targeted rules, aggressive context management — Claude Code stays precise on a monorepo. You get the speed you want without the token bill you don't.
Before you start
You need:
- Claude Code 1.5+ installed and working on a large repo.
- A monorepo you actually work in. The guide makes more sense with a concrete codebase to configure against.
- 30 minutes. Mostly in config files.
Step 1: Understand what Claude reads by default
Run /context in an active session. Claude shows you exactly what's in its current window:
- CLAUDE.md files (root + any parent/subpath).
- Files you've mentioned or Claude has opened.
- Tool definitions.
- The conversation so far.
Look at the line counts. On a monorepo, you'll often see dozens of files loaded from "looking around," many irrelevant to the task. That's the problem to fix.
Step 2: Scope with a monorepo-aware CLAUDE.md
At the repo root, your CLAUDE.md should be small — only truly repo-wide rules. Monorepo context belongs in sub-path CLAUDE.md files:
/CLAUDE.md # Repo-wide conventions, very short
/apps/web/CLAUDE.md # Next.js app conventions
/apps/api/CLAUDE.md # API server conventions
/packages/ui/CLAUDE.md # Shared UI package conventionsClaude walks the directory tree from the file it's editing, reading every CLAUDE.md along the way. So when you're editing in apps/web/, Claude reads apps/web/CLAUDE.md + CLAUDE.md — not apps/api/CLAUDE.md.
This alone cuts CLAUDE.md overhead by 60-70% in a typical monorepo.
Step 3: Configure an ignore list
Claude Code respects a .claudeignore (or equivalent — check your version's name). Use it like .gitignore:
# .claudeignore
node_modules/
dist/
.next/
coverage/
*.lock
*.min.js
pnpm-lock.yaml
# Monorepo apps you're not touching right now
apps/legacy-dashboard/Anything in .claudeignore is invisible to Claude — no reads, no greps, nothing. Scoping to the app you're actually working in is the biggest single token win.
For per-session scoping, some versions let you pass --project-dir apps/web to launch Claude Code already scoped to that sub-app. If available, use it for narrow-scope sessions.
Step 4: Avoid open-ended exploration prompts
Prompts like "give me an overview of this codebase" are monorepo budget-killers. Claude will try to read dozens of files to answer, costing you tokens and rarely producing insight you didn't already have.
Replace with scoped questions:
- "How does
apps/web/src/app/api/checkout/route.tshandle the webhook signature?" - "Find all uses of
useAuth()inapps/web/and list them." - "Summarize the changes in the last 3 commits that touched
packages/ui/."
Specific location + specific question = a small, focused read. Claude answers in a few file reads instead of forty.
Step 5: Use /compact or /clear aggressively
Claude Code has commands to reduce the live context:
/clear— wipes the conversation history, keeping only CLAUDE.md and current task. Use between distinct tasks./compact— asks Claude to summarize the current conversation into a shorter form, replacing the verbose history. Use mid-task when context is getting heavy.
Rule of thumb: if a conversation has 30+ turns of tool use, /compact. If you're starting a new task (different feature, different app), /clear.
Step 6: Scope tool use with rule files
For very large repos, limit what Claude can read via permission rules. In .claude/settings.json (or your version's config path), restrict Read and Glob to paths you're working in:
{
"permissions": {
"allow": {
"Read": ["apps/web/**", "packages/ui/**", "CLAUDE.md"],
"Glob": ["apps/web/**", "packages/ui/**"]
},
"deny": {
"Read": ["apps/legacy-*/**"]
}
}
}Now Claude physically cannot read the parts of the monorepo you're not working in. Safer and cheaper.
Check your Claude Code version's docs for the exact permissions format — it's stabilized but the key names can shift.
Step 7: Cache what's stable
For long sessions in a big repo, the initial context (CLAUDE.md + tool definitions) is stable while the conversation grows. That's a prompt caching opportunity — see How Do I Keep My Claude Prompt Cache Hit Rate High? — though Claude Code handles caching under the hood on supported models. Verify in your session logs that cached reads are happening; if not, update to the latest Claude Code.
Step 8: Build a "starting prompt" that skips orientation
Instead of letting Claude figure out where to start on every task, give it a preamble:
/clear
We're working in apps/web/, a Next.js 16 app. The feature I'm building is the
Stripe webhook handler at apps/web/src/app/api/webhooks/stripe/route.ts. It
currently handles checkout.session.completed; we're adding invoice.paid.
Related files: apps/web/src/lib/stripe.ts (client), apps/web/prisma/schema.prisma
(Subscription model). Start by reading those three files.You've done the orientation Claude would have paid 20 file reads to do. The task proceeds from a small, correct initial context.
Verify it worked
1. Cold-start context is small. Open a fresh Claude Code session, type /context. Line count should be under a few thousand — mostly CLAUDE.md and tool definitions, not app code.
2. Tasks finish with fewer file reads. A medium task that used to take 40 Read tool calls should now take 10-15. Watch the tool-use indicators.
3. Cost per session drops. If you're on API billing, compare a typical session's cost before and after configuration. Target: 50%+ reduction.
Where this breaks
- Ignoring files you actually need. A
.claudeignorethat excludespackages/shared/means Claude can't see your shared utilities, which are probably relevant. Start permissive, tighten as you notice over-reads. - Stale sub-path CLAUDE.md files. Conventions evolve; sub-path CLAUDE.md files get stale fast because nobody looks at them unless they're actively working there. Add a reminder in root CLAUDE.md: "Sub-path CLAUDE.md files exist at X, Y, Z — keep them current."
- Claude hallucinating about code it can't see. When you restrict reads aggressively, Claude sometimes confidently describes code it didn't actually read. Ask "show me the line you're referring to" — if Claude can't cite, it was guessing. Widen the scope if this happens often.
- Per-app permissions drift from actual app structure. Adding a new sub-app that isn't in the allowlist means Claude can't see it on day one. Update
.claude/settings.jsonwhen you add apps, same time you update other repo-level configs. - Compact losing important context.
/compactis a summary, not a lossless compression. Details in the compacted portion can disappear. Don't compact right before a precision task; compact after.
What to try next
- How Do I Write a CLAUDE.md That Actually Changes Claude's Behavior? — the foundation of per-sub-path scoping.
- How Do I Keep My Claude Prompt Cache Hit Rate High? — the cost lever that matters most on long Claude Code sessions in big repos.
- How Do I Set Up Claude Code Hooks for Auto-Quality? — quality gates matter more in a big repo where a small mistake can cascade. Hooks run the gates automatically.
Let's talk about your AI + SEO stack
If you'd rather skip the how-to and have it shipped for you, that's what I do. Start a conversation and we'll figure out the fastest path to results.
Let's Talk