How to Use Claude Code in Large Codebases: A Practical Guide
How to use Claude Code in large codebases comes down to one habit: limit what it has to look at. Most advice says to feed it more context, and I think that is backwards. Give it a short map of the repo, a narrow task and a test that proves success, and it works well. Leave it to wander and it guesses.
Key takeaways- Claude Code finds code by searching, not by reading the whole repo, so your job is to steer that search with a layered CLAUDE.md and named entry files.- Plan in read-only mode first, and reject any plan that touches modules you did not name.- Work in slices that each end green and committed. Git is your real undo, not the session.- Long sessions degrade and cross-service changes can be subtly wrong. Review every diff, and restart with a narrower prompt when the session drifts.- Keep CLAUDE.md short. One widely shared rule of thumb is under 200 lines, ideally under 100.
The short answer: give Claude a map, not the whole repo
Claude Code explores with search tools such as grep and glob rather than a pre-built index of your repository. That is how the tool is described, and details change between versions, so check the official documentation for current behavior. The consequence is practical. In a big repo, the quality of the search decides the quality of the answer.
Context is the other constraint. MindStudio's April 2026 comparison of memory systems says the model has no persistent state, so each session starts from zero. It also notes that large codebases eat context fast. That is a vendor's explanation, not a measurement. It does match the behavior I would expect: whatever you want Claude to know must be written down or re-read every time.
Three levers do most of the work:
- Layered CLAUDE.md files. Small, specific, close to the code they describe.
- Read-only planning before edits. You approve the scope before anything changes.
- Small tasks with automated checks. Each slice ends green, so failures surface early.
Two limits are worth planning for. Long sessions degrade as context fills with file contents and dead ends. Cross-service changes are easy to get subtly wrong, because Claude cannot honor a contract it never opened. On a platform with zero-downtime releases, producers and consumers deploy at different moments. A field rename that looks correct in one service can break the other during the rollout. Claude will not notice unless you tell it to look.
If you are starting a product instead of inheriting one, a scaffold such as MakeV1: Ship your SaaS with the hard parts already done. keeps the codebase small. MakeV1 is one of my side projects. Most of this guide matters less when the repo is small and its conventions are fresh.
Prerequisites
Set these up before the first session. Skipping them is the most common reason people conclude the tool "doesn't work on big repos".
- Tool and tree. Claude Code installed and authenticated, a clean git working tree, and a branch you can throw away.
- Fast checks. A test command, linter and type check that run from the terminal in reasonable time, ideally scoped to one package. If the only test command is a 30-minute full suite, fix that first. Every later step depends on quick feedback.
- Repo orientation. Know where services, shared libraries, generated code and vendored code live. You cannot steer a search through a layout you cannot describe. My notes on structuring a codebase for scale and maintainability cover how to make that layout legible.
- Permission to send the code. Check your company's data and security policy before the first session.
On that last point, account type matters. Anthropic's privacy center separates commercial customers (API, Console, Team and Enterprise) from consumers (Free, Pro and Max). That tells you the terms differ by account type. It does not tell you what your terms say.
A secondary report from Anonyome describes a September 2025 consumer terms update with a training toggle pre-set to on. Treat that as a reason to read the current terms yourself, not as a summary of them.
If you need an audit trail, check the plan. Adelia Risk, a security consultancy, reports that Team-plan chats produce no reviewable log and that the server-side audit log comes only with Enterprise. Plan features change, so confirm against Anthropic's documentation.
Practical rule: Do not start a session until your tests run fast, your scope is named, and your data policy says yes.
Step 1: Write a layered CLAUDE.md instead of one giant file
Run /init for a first draft, then cut it hard. The draft is a scan of your project, so it will contain things Claude could discover alone. Keep only build and test commands, architecture boundaries, and conventions that are easy to get wrong.
Size matters because the file is read into every session. One designer's cheatsheet suggests keeping it under 200 lines, ideally under 100. That is a rule of thumb from one practitioner, not a tested threshold. The direction is right, though: each line you keep is paid for in every session.
Example: an /init draft of 340 lines gets trimmed to about 80. You delete the directory tour Claude can recover with a search, and the explanations of obvious frameworks. You keep the commands and the five rules that were learned the hard way.
Layer the rest instead of growing the root:
Layer | Put there | Watch out for |
|---|---|---|
Root | Build and test commands, architecture boundaries, easy-to-miss conventions | Every line is loaded every session; cut anything Claude can find by searching |
| That package's commands, local rules, don'ts | Contradicting the root; write only what differs |
| A pointer to the existing document | Imported text still costs context; point at a short, current doc |
| Topic rules that apply to certain folders | Layout and loading behavior are version-dependent; one guide describes this folder, so check the docs |
Personal | Your own working style | Teammates never see it; keep team rules in the repo |
Package-level files are the main scaling tool. Claude loads them when it works in that area, so the root stays small. Imports beat copies for the same reason: a pasted copy of your API conventions goes stale, and you pay for it anyway.
Write the don'ts, because that is where the value is. A package file might look like this:
# services/billing
## Commands
- Test: `make test-billing`
- Lint: `make lint-billing`
## Boundaries
- Never import from `services/listings/internal`. Use the client in `packages/shared-clients`.
## Don'ts
- Never hand-edit `src/generated/`. Run `make codegen`.
- `legacy_invoice/` is deprecated. Do not extend it.
- Schema changes follow @docs/adr/0007-expand-contract-migrations.md. Do not improvise a migration.Example only; the paths and commands are placeholders. Test the result by asking Claude to explain the rules back before it edits. If it misstates one, the wording is ambiguous.
Step 2: Scope the task and plan in read-only mode first
Start in plan mode (Shift+Tab in current versions) and name the entry files, the boundary and the success test. Vague prompts make Claude search wide and guess. A scoped prompt shrinks the search before it starts.
Example prompt:
Goal: stop rejecting invoices with a zero-cent line item.
Start in services/billing/src/validate.ts and its test file.
Do not touch services/listings or packages/shared-clients.
Done when `make test-billing` passes and a new test covers a zero-cent line.Three habits make planning pay off:
- Send exploration to subagents. "Where is X used?" fills context with file contents. Ask for a summary and file paths back, so the main session stays clean.
- Deny reads of noise and secrets. Block secrets, build output and vendored directories in your settings permissions. The
settings.jsonfile is where one guide places permissions, but exact rule syntax is version-dependent, so use the official docs. This is a security control first and a noise filter second. - Review the plan like a design doc. Reject it if it touches modules you did not name. Optionally save approved plans to a markdown file, so a restart does not lose the decision.
The cost of skipping this is concrete. Thomas Landgraf's write-up on memory and tokens lists three cost drivers: the number of calls, tokens per call and model choice. He warns against asking Claude to "figure it out" repeatedly, which re-reads the same files. That is one practitioner's account, not a benchmark. It still explains why an unscoped prompt costs more than a scoped one.
Practical rule: A plan that touches a module you did not name is a rejected plan, however reasonable it sounds.
Step 3: Execute in small slices with checks that run automatically
Split the work into steps that each leave tests green and fit in one commit. Example: a field rename across three packages becomes three slices.
- Slice one: add the new field alongside the old one.
- Slice two: move readers and writers to the new field.
- Slice three: remove the old field after consumers have deployed.
Each slice is reviewable alone, and each can be reverted without touching the others. Between unrelated tasks, run /clear. Use /compact only when you are continuing the same task and want to keep its thread.
A hook is optional but worth it. Hooks can run your formatter and scoped tests after edits, so failures reach Claude immediately instead of your reviewer. Configuration details vary by version, so follow the official docs. The honest limit is speed: a hook that runs a 20-minute suite after every edit will make the session unusable. Scope it to the package or skip it.
For parallel tasks, use separate git worktrees with one session each. Sessions then never edit the same files. Parallel work also burns usage faster. Anthropic's July 2025 weekly-limits announcement, quoted on Hacker News, said heavy Opus users with large codebases or multiple parallel instances would hit limits sooner. The figures were specific to those plans at that time and may have changed. Treat it as a clue that parallelism has a cost, not as a current limit.
Review every diff yourself. Claude's confidence tells you nothing about cross-service contracts it never opened. If you are working on a legacy project, I wrote up rebuilding a 10-year-old open source package with Cursor and Claude, which shows the same slice-and-verify loop on old code.
Verify the result and roll back safely
Verification is a checklist, not a feeling:
- Run the full test suite for the touched packages, not just the new test.
- Run type checks and the linter.
- Read the diff for unrelated edits: reformatted files, renamed variables, touched lockfiles.
- Grep for callers of any changed interface, including other services and scripts. This is the check that catches the cross-service failure from earlier.
My process for how I review AI-generated code goes deeper. The short version: review it like a stranger's pull request.
Commit after every green slice, so rollback is a git operation and not an argument with the model:
# Undo one bad slice, keeping history
git revert <commit-sha>
# Discard everything since the last good commit (destructive)
git reset --hard <last-good-sha>Use Esc-Esc or /rewind for in-session mistakes, but treat git as the real undo. Rewind may not cover everything a session did, such as changes made by shell commands. Never run a session with uncommitted work you cannot afford to lose.
If the session drifts or repeats itself, stop. Write down what you learned in the nearest CLAUDE.md, clear the context, and restart with a narrower prompt. That restart costs a few minutes. Pushing on costs a corrupted diff.
Practical rule: Commit every green slice, and let git be the undo.
Frequently asked questions
Should CLAUDE.md be committed to the repository?
Yes, for the shared project file. The cheatsheet cited earlier recommends committing it so the whole team gets consistent behavior, and I agree. Keep personal preferences in your user-level file or in a gitignored local settings file, and never put secrets or internal hostnames in anything you commit.
Does Claude Code work in monorepos with several languages?
It should, because it works through search and shell commands rather than one language's tooling. I have no source that quantifies how well it handles mixed stacks, so verify on a small task first. Put each language's build, test and lint commands in that package's CLAUDE.md, and expect a language-aware IDE refactor to be more reliable than a search-based rename.
How do I keep token usage down on a big codebase?
Scope tasks so Claude searches less, clear context between tasks, and send exploration to subagents. Prefer the cheaper model for routine slices. Landgraf's write-up notes that Opus costs significantly more per token than Sonnet. Watch MCP servers too: a community discussion describes unpaginated tool responses flooding context, with context-limit errors reported in some clients, so prefer tools that return limited results.
Run this checklist on your next task
- Pick one package and write its CLAUDE.md: commands, boundaries and three don'ts. Trim the root file until each line earns its place.
- Plan in read-only mode. Name the entry files and the test that proves success, and approve the plan before any edit.
- Work in slices that each end green and committed. Clear context between tasks, and use worktrees for parallel runs.
- Verify with the package's full tests, type checks and a grep for callers of anything you changed. Read the diff like a stranger's pull request.
- After the session, add the one mistake Claude made to the nearest CLAUDE.md. If the session drifted, restart with a narrower prompt instead of pushing on.