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

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

Jake McCluskeyUpdated Advanced40 min
Back to guides

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:

text
/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 conventions

Claude 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:

text
# .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.ts handle the webhook signature?"
  • "Find all uses of useAuth() in apps/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:

json
{
  "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:

text
/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 .claudeignore that excludes packages/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.json when you add apps, same time you update other repo-level configs.
  • Compact losing important context. /compact is 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

Want this built for you instead?

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
Questions from readers

Frequently asked

Where should I put CLAUDE.md files in a monorepo?

Small root CLAUDE.md with repo-wide rules only. Sub-path CLAUDE.md files (apps/web/CLAUDE.md, packages/ui/CLAUDE.md) for app- or package-specific conventions. Claude walks the tree from the file being edited and merges the stack — so you pay for only the relevant files' rules.

Does .claudeignore work the same as .gitignore?

Similar syntax, different purpose. .claudeignore tells Claude what to skip when reading/searching, not what to exclude from git. You can (and often should) include things in .claudeignore that are tracked in git — large generated files, lockfiles, legacy apps — just to keep them out of Claude's working view.

What's the single biggest token win?

Ignoring the apps you're not touching. In a typical monorepo, you work in one app at a time; everything else just dilutes Claude's attention. A .claudeignore that excludes the other apps cuts token usage 50-70% in most sessions.

Should I use /compact or /clear between tasks?

/clear for distinct new tasks — different feature, different app. /compact mid-task when context is growing heavy but you need to keep the thread. Running /compact right before a precision task is risky; details may get lost in the summary.

How do permissions help with cost?

Scoped Read and Glob permissions prevent Claude from reading outside your current work area. Even a well-intentioned 'let me check if there's a pattern elsewhere' becomes a no-op, which is what you want in a monorepo. Sessions stay tight; token usage is predictable.

GUIDED IMPLEMENTATION

Want help running this in your business?

The guide above is the playbook. If you'd rather have someone walk it through with you (or just build the thing), book a 30-min scoping call. We'll map your stack, name the realistic timeline, and tell you straight if it's a fit.