How to use Claude Code with large codebases without burning tokens
Claude Code is most effective when you treat it like a senior engineer with a terminal, not like a chat box that needs the whole repository pasted into context. Large codebases can contain millions of tokens across source, tests, generated files, lockfiles, build output, and documentation. If you send too much at once, you pay in cost, latency, and worse answers.
The goal is simple: give Claude Code enough context to act correctly, but force it to discover that context selectively. The best workflow combines repository maps, narrow prompts, reusable instructions, and verification commands.
Start with a token-light mental model
Do not ask Claude Code to “understand the whole repo.” Ask it to answer a bounded question. Good prompts identify the feature area, likely files, expected behavior, and constraints.
Weak prompt:
Read this repository and fix the payment bug.
Better prompt:
Investigate why failed Stripe payments are sometimes marked as paid.
Start with src/billing, tests/billing, and the PaymentStatus enum.
Do not edit files yet. First summarize the relevant flow and list likely fix points.
This keeps Claude in exploration mode and prevents it from loading unrelated services, UI code, or generated artifacts.
Create a repository map instead of pasting code
For large repositories, a compact map is worth more than thousands of raw lines. Generate a file that lists important directories, entry points, owners, and test commands. Keep it short and current.
# Create a lightweight repository map without dumping file contents.
# Exclude generated, dependency, and build directories.
find . \
-path './node_modules' -prune -o \
-path './dist' -prune -o \
-path './build' -prune -o \
-path './.git' -prune -o \
-type f \
| sed 's#^./##' \
| sort \
> docs/repo-file-list.txt
Then ask Claude to use the map as an index, not as the full source of truth:
Use docs/repo-file-list.txt only to identify likely files.
Open source files selectively. Do not read broad directories unless needed.
This pattern gives Claude orientation while keeping high-volume code out of the conversation.
Use CLAUDE.md as a context firewall
A well-written CLAUDE.md file prevents repeated explanations. It should contain stable facts: architecture, commands, conventions, and files to avoid. It should not contain long implementation details.
# CLAUDE.md
## Project shape
- Backend: services/api, Python FastAPI.
- Frontend: apps/web, React and TypeScript.
- Shared types: packages/contracts.
## Before editing
- Prefer small patches.
- Search before reading large files.
- Do not inspect generated clients unless explicitly requested.
## Commands
- Backend tests: `pytest services/api/tests`
- Frontend tests: `pnpm --filter web test`
- Type check: `pnpm typecheck`
## Ignore for normal tasks
- node_modules
- dist
- coverage
- generated
- snapshots larger than 200 lines
This works like a standing instruction set. It saves tokens because you stop repeating project basics in every prompt.
Make Claude search before it reads
Reading entire files is expensive. Searching is cheap and precise. Ask Claude Code to use names, symbols, routes, error messages, and test names to locate relevant code first.
Find references to `PaymentStatus.PAID`, `markPaid`, and the webhook route.
Use search first. Read only the files that define or directly call those symbols.
You can also run the first search yourself and paste only the result list:
# Show file names only, not full matching lines.
rg --files-with-matches 'PaymentStatus\.PAID|markPaid|stripe webhook' services tests
File names and symbol names are high-signal context. Large code blocks are often not.
Work in phases: map, plan, patch, verify
For non-trivial changes, split the task into phases. This avoids a common token failure mode: Claude reads too much, edits too soon, then spends more tokens correcting itself.
Phase 1: Map
Do not edit files. Build a concise map of the payment status flow.
Include only files, functions, and database fields relevant to failed payments.
Phase 2: Plan
Propose the smallest safe fix. Include test coverage.
Call out any assumptions before editing.
Phase 3: Patch
Implement the approved plan. Keep the diff minimal.
Do not refactor unrelated code.
Phase 4: Verify
Run the narrowest relevant tests first. If they pass, run the broader billing test suite.
This phased style reduces context churn and makes each Claude response easier to inspect.
Prefer diffs over full files
Once edits begin, keep Claude focused on changes. Ask it to reason from git diff, not from complete files.
# Review only current changes.
git diff -- src/billing tests/billing
# Show changed file names for a compact status check.
git diff --name-only
Then prompt:
Review the current diff for correctness, missing tests, and unintended behavior changes.
Do not re-read unrelated files unless the diff requires it.
Diffs are dense. They contain exactly what changed and enough surrounding lines to reason about behavior.
Exclude noisy files aggressively
Large token burns often come from files nobody meant to read: lockfiles, snapshots, generated API clients, minified assets, and coverage reports. Keep them out of normal workflows.
# Example: remove common noise from ad hoc search results.
rg 'refund|payment|invoice' \
--glob '!node_modules/**' \
--glob '!dist/**' \
--glob '!coverage/**' \
--glob '!generated/**' \
--glob '!*.snap' \
--glob '!pnpm-lock.yaml'
If generated code is relevant, ask Claude to inspect the schema or source generator instead of the generated output.
Add tiny helper scripts for large monorepos
In monorepos, a script that maps ownership and package boundaries can save thousands of tokens per session.
#!/usr/bin/env python3
# scripts/compact_tree.py
# Print a compact tree with a shallow depth and noisy directories removed.
from pathlib import Path
SKIP = {'.git', 'node_modules', 'dist', 'build', 'coverage', 'generated'}
MAX_DEPTH = 3
def walk(path: Path, depth: int = 0):
if depth > MAX_DEPTH or path.name in SKIP:
return
indent = ' ' * depth
if path.is_dir():
print(f'{indent}{path.name}/')
for child in sorted(path.iterdir(), key=lambda p: (not p.is_dir(), p.name)):
walk(child, depth + 1)
else:
print(f'{indent}{path.name}')
walk(Path('.'))
Run it and let Claude use the output to choose where to look next:
python scripts/compact_tree.py > docs/compact-tree.txt
Use summaries as handoff checkpoints
Long sessions accumulate context. Periodically ask Claude to write a compact checkpoint that captures only durable findings.
Summarize this investigation in under 250 words.
Include: relevant files, confirmed behavior, decisions made, commands run, and remaining tasks.
Omit speculation and old dead ends.
You can paste that summary into a fresh session or keep it in a temporary note. This is often cheaper and cleaner than carrying a long conversation forever.
Final checklist
Use Claude Code with large codebases by narrowing scope, searching before reading, relying on compact maps, and reviewing diffs instead of full files. Put stable instructions in CLAUDE.md. Exclude noisy artifacts. Work in phases. Ask for summaries when context grows.
The best token-saving habit is discipline: never provide broad context just because it is available. Provide the smallest context that lets Claude Code make the next correct move.