Managing Claude Code's Context on Large Codebases

aiclaude-codedeveloper-toolsproductivity
Gerald VillorenteSeptember 13, 20266 min read

I asked Claude Code a pretty practical question the other day: this repo is a monorepo — a Next.js app, an Express API, a shared db package — and every new session it seemed to re-discover the same things. Where the auth middleware lives. How the Docker Compose files are wired. Why the homepage fetches data a certain way. It's not that the codebase is huge by industry standards, but a long working session adds up, and I wanted to know: what's the actual fix for "big-ish codebase, expensive re-scanning, no memory between sessions"?

The answer was good enough that it's worth sharing on its own, separate from anything specific to this site. It breaks the problem into three genuinely different things people tend to lump together — not re-discovering what you already learned, not scanning broadly in the first place, and not paying full price even when you do need a lot of context — and each one has a different fix.

The three problems are not the same problem

It's tempting to reach for "just give it a bigger context window" as the fix for all of this. That solves exactly one of the three problems — size — and does nothing for the other two. A 1-million-token window that gets re-filled with the same re-discovery work every session is still slow and still expensive; it just fails later instead of sooner. Worth keeping the three apart:

  • Persistence: information Claude figured out in a past session should not have to be re-derived from scratch in the next one.

  • Scope: a search or a task should only pull in the files actually relevant to it, not walk the whole tree "to be safe."

  • Cost: even necessary, correctly-scoped context has a price, and that price can be reduced independently of how much of it there is.

Persistence: write it down once, in a place that gets loaded automatically

The most direct fix is a CLAUDE.md file at the project root — Claude Code reads it automatically at the start of every session. For a monorepo, nested CLAUDE.md files inside each package or service work the same way, scoped to that directory. The discipline that actually matters here is what goes in it: not a restated file tree or a summary of what a directory obviously contains, but the things that can't be cheaply re-derived by reading the code — why a decision was made, a gotcha that cost time to find once, a convention that isn't visible from any single file.

A concrete example from this project: the fact that Next.js's rewrites() function is evaluated once at build time, not per server boot, is not something you'd guess from reading next.config.ts — you'd have to actually hit the bug (which I did, on this site's first production deploy) to know it matters. That's exactly the kind of note worth putting in a CLAUDE.md, so the next session — or the next person — doesn't pay for that discovery twice.

A lower-effort version of the same idea, for a codebase that's already large and undocumented: have a subagent generate a one-time CODEBASE_INDEX.md or ARCHITECTURE.md that future sessions read instead of walking the tree, and regenerate it after major refactors rather than maintaining it by hand continuously.

Scope: don't scan broadly to begin with

This is where subagents earn their keep, and it's a distinction worth understanding: a subagent gets its own isolated context window. If you ask it to go figure out how a particular feature is implemented across 40 files, only its summary comes back to the main conversation — not the 40 files' worth of tokens it took to get there. That's the difference between "explore this and tell me" polluting your primary thread forever, versus staying contained to a disposable side-conversation.

Paired with that: search before you read. Grep or Glob for candidates first, rather than asking for "understand this codebase," which invites wholesale reads of things that turn out to be irrelevant. Planning up front — deciding what you actually need to look at before touching any files — cuts down on the cascading pattern where reading file A reveals you need file B, reading B reveals you need C, and so on, each one dragging more into a context window that never gets smaller.

For anything you do repeatedly — a deploy checklist, a recurring review pass, a data-migration script — packaging it as a reusable skill or tool means the procedure and the domain knowledge behind it live outside the conversation entirely. You invoke it; you don't re-explain it from scratch every time you need it.

Managing what's already there

Even with good discipline, a long session accumulates context. Compacting the conversation summarizes history to free up room without losing the thread; clearing resets entirely when you're genuinely starting fresh. Neither reduces the total tokens a task costs — they just let a long-running session keep going instead of hitting a hard wall partway through.

Size and cost are two different levers

A large context window is a size fix, not a cost fix — filling it on every single request is expensive regardless of whether that request actually needed all of it. The lever that actually addresses cost is prompt caching: static reference material you reuse across many calls — an index file, a big system prompt, reference documentation — gets billed at full price once, and subsequent calls that reuse it within the cache window pay a fraction of that. There's also a mechanism for automatically discarding stale tool output from a long-running agent loop, so a session doesn't accumulate context unboundedly turn after turn just from routine tool use.

When the codebase is bigger than all of this can comfortably cover

The honest fallback, once a codebase outgrows what indexing plus targeted search can handle gracefully, is a retrieval layer — embeddings, or even something as simple as a full-text search index — sitting in front of the repo, so the question "what handles X" returns a small relevant set of snippets instead of triggering a scan. That's infrastructure you build and maintain once, not a setting you flip, and it's worth being clear-eyed that it's a bigger commitment than everything above it.

What it adds up to

For most projects — including this one — the combination doing the actual heavy lifting is: a well-maintained CLAUDE.md (root plus nested, for the why-not-the-what), subagents for anything exploratory so a search doesn't become part of the permanent conversation, and a search-before-you-read habit. Caching and window size handle the mechanics underneath that; compacting is the safety valve for when a session runs long regardless.

None of this is exotic, and none of it requires switching tools or workflows. It's mostly a matter of writing down the things worth not re-learning, and being deliberate about what actually needs to enter the conversation in the first place.

Comments

Comments disabled — configure NEXT_PUBLIC_GISCUS_* env vars.