Using Claude Code on a Large Codebase
On a big repository, Claude Code's quality depends on what's in its context. How to structure CLAUDE.md files across a monorepo, point it at the right code, delegate exploration to subagents, keep sessions focused, give it fast feedback loops, and plan multi-step changes that span many files.
On a small project, Claude Code can read everything relevant in a few steps. On a repository with thousands of files, several services, and years of conventions, it can't — and what it chooses to read, and what fills its context along the way, decides whether it produces a clean change or a plausible mess. The techniques below are about controlling that.
1. Layer your CLAUDE.md files
Claude Code reads CLAUDE.md from the project root at session start, and picks up CLAUDE.md files in subdirectories when it works in those areas. Use that to scope knowledge:
CLAUDE.md # repo-wide: layout, commands, conventions, don'ts
apps/web/CLAUDE.md # Next.js app specifics
apps/api/CLAUDE.md # API: error handling, auth middleware, testing
packages/db/CLAUDE.md # migrations rules, naming, how to regenerate types
Keep the root file short — it's loaded every session and costs context every time. Put a map there:
## Layout
- apps/web — customer-facing Next.js app
- apps/api — Fastify API; routes in src/routes, services in src/services
- packages/db — Drizzle schema and migrations (see packages/db/CLAUDE.md)
- packages/ui — shared components; never import app code from here
## Commands
- Test one package: pnpm --filter <name> test
- Type check everything: pnpm typecheck
You can also pull other files in with @path imports from CLAUDE.md, but every import adds to the baseline context — import sparingly. (How to Write a CLAUDE.md.)
2. Point, don't make it search
Every file Claude opens and every search result it reads stays in context. Vague requests trigger wide searches:
- ❌ "Fix the bug where invoices show the wrong tax."
- ✅ "Invoices show the wrong tax for EU customers. The calculation is in
apps/api/src/services/tax.ts; the rate table ispackages/db/src/schema/tax-rates.ts. Start there."
Use @ to add specific files to the conversation directly. If you don't know where something lives, ask for a map first ("Which files are involved in invoice tax calculation? List them, don't change anything"), then start the real task with that list.
3. Delegate exploration to subagents
A subagent works in its own context and returns only a summary. Exploration — reading dozens of files to understand a flow — is exactly the work you want out of your main session:
Use a subagent to trace how a webhook from Stripe flows through the system to the
subscriptionstable. Report the files and functions involved, in order, in under 30 lines.
The main session gets the 30-line summary instead of 40 files of source. (Claude Code Subagents.)
4. Keep sessions narrow
- One task per session.
/clearbetween tasks. - Compact deliberately at natural breaks, saying what to keep:
/compact keep the list of call sites we still need to update. - Check
/contextwhen quality drops — a huge test log or a generated file may be crowding out your instructions. - Write state to a file for long tasks. Ask Claude to maintain
PLAN.mdwith the checklist of files to change and what's done. It survives compaction and lets you resume in a fresh session. (What Is a Context Window?.)
5. Plan multi-file changes
For anything that touches many files — renaming a concept, changing an API contract, migrating a library — start in plan mode:
- Claude investigates and proposes: every call site, the order of changes, the migration strategy, how it will verify.
- You correct the plan while it's cheap.
- Then execute in batches, verifying between them.
(Claude Code Plan Mode.) For very wide mechanical changes, split the work across parallel sessions on separate branches or worktrees, each owning a slice. (Run Parallel Claude Code Agents With Git Worktrees.)
6. Give it fast, scoped feedback
On a large repo, "run the tests" might mean 20 minutes. Teach Claude the scoped commands:
- Test a single package or file.
- Type check only the affected project.
- Lint only changed files.
Put them in CLAUDE.md, and pre-approve them in .claude/settings.json so they run without prompts. (Claude Code Settings Explained.) Fast, specific feedback is what lets the agent iterate to a correct change instead of guessing. A PostToolUse hook that type checks the edited package gives feedback automatically. (Claude Code Hooks.)
Also ask for quiet output: failing tests only, not the whole suite's success lines.
7. Encode conventions as tools, not prose
"Follow our patterns" in CLAUDE.md is weak on a large codebase with several generations of patterns. Stronger:
- Lint rules that enforce import boundaries and ban deprecated APIs.
- Codegen/scaffold scripts (
pnpm new:route billing/refund) that produce the canonical shape. - Skills that package multi-step procedures — "add an API endpoint," "write a migration" — with the exact steps and checks. (Claude Code Skills.)
- Reference implementations: "When adding a route, copy the structure of
routes/invoices.ts."
8. Exclude the noise
Generated code, vendored dependencies, build output, fixtures, and huge lockfiles can drown out real code in searches. Make sure .gitignore covers build artefacts, and tell Claude which directories are generated and should never be edited by hand. Deny Read on paths that are pure noise if they keep getting pulled in.
9. Review like it's a large PR — because it is
Large-codebase changes fail at the seams: a call site in another package, a serialiser nobody remembered, a background job using the old field. Ask Claude to list every place the changed contract is used and show how each was handled, and use /code-review on the diff before merging. (Review AI-Generated Pull Requests.)
A starter prompt for big changes
We're renaming
accountIdtoworkspaceIdacross the API and web app. Use plan mode. First, use a subagent to find every usage — code, SQL, API schemas, tests, fixtures — and group them by package. Propose an order that keeps the build green after each step, including a database migration that's safe with old and new code running. Track progress in PLAN.md. Verify each package with its scoped typecheck and tests before moving on.
EasySpawn gives Claude Code a persistent workspace where a large repository stays cloned, dependencies stay installed, and PLAN.md and your CLAUDE.md files are there tomorrow — so long, multi-session changes pick up where they left off. See how it works or join the waitlist.
Related: Why AI Agents Forget · Monorepo vs Polyrepo · Claude Code Settings Explained
Keep reading
How to Resume a Claude Code Session (and What Resuming Can't Bring Back)
claude --continue and claude --resume reopen yesterday's conversation in seconds. But a resumed session restores the conversation, not the world it was working in. The commands, the habits that make resuming reliable, and the gap between conversation state and environment state.
How to Write a CLAUDE.md That Actually Changes What Claude Does
Most CLAUDE.md files are either empty or a wall of generic advice Claude would have followed anyway. What to put in one, what to leave out, how the files load, and how to tell whether yours is working.