Using Claude Code in Large Codebases and Monorepos

Using Claude Code in Large Codebases and Monorepos

A Claude Code large codebase setup is mostly about one idea: show Claude only the part of the repo your task touches. Claude Code works at any size, but in a big monorepo the small-project defaults can fill the context window with instructions and file reads that have nothing to do with your task. That costs tokens and makes answers less sharp.

In this guide you will learn where to start Claude, how to split CLAUDE.md files by folder, how to block build output, how to reach a sibling package, and how to check out only the folders you need in a worktree. We built a tiny three-package monorepo and tested each step for real.

This is Part 44 of 53 in our Claude Code tutorials series. In the previous part we covered Claude Code security; this part is about keeping Claude focused when the repo gets huge.

Tested with Claude Code v2.1.310 on October 25, 2026, on macOS, inside a small throwaway git monorepo with packages named api, web and shared.

Quick Summary: Claude Code in a Large Codebase

I want toUse thisCommitted or personal?
Load only the rules for the code I touchA CLAUDE.md in each package or subsystemCommitted
Skip other teams’ CLAUDE.md filesclaudeMdExcludesEither (local is common)
Stop Claude opening build output or vendored codeRead deny rules in permissions.denyEither
Find definitions without scanning filesA code intelligence pluginPersonal or enabledPlugins
Make worktrees check out fewer foldersworktree.sparsePathsEither
Edit a sibling package from my package–add-dir or additionalDirectoriesEither
Give each package its own proceduresSkills in that folder’s .claude/skills/Committed

Why Large Codebases Need a Different Setup

In a small project, one CLAUDE.md and a quick look around the folder are enough. In a repo with dozens of packages or millions of lines, that same approach gets expensive. A single root CLAUDE.md either grows to cover every team’s rules or stays too vague to help.

File reads are the other cost. If Claude has to grep through generated code or a vendored SDK to find one function, it spends your context on noise. The settings in this guide all do one job: they trim what Claude sees down to what the task needs.

In a big repo, less context usually means better answers, not worse ones.

Each setting is independent, so you can stack only the ones your repo needs. If you are new to how context works, our guide to the context window explains /context and /compact first.

Diagram of five layers that keep Claude Code focused in a large codebase: per-folder CLAUDE.md, claudeMdExcludes, Read deny rules, code intelligence plugin, sparse worktrees and per-folder skills
Five independent layers you can stack to keep Claude focused in a big repo

Step 1: Choose Where to Start Claude

Where you run the claude command matters more than any setting. It decides which files Claude can edit without asking, which CLAUDE.md files load at launch, and which project settings apply.

Start fromFile accessCLAUDE.md loaded at launchBest for
Repository rootEvery fileRoot only; package files load on demandTasks that span many packages
A package or subfolderThat folder only, until you grant moreThat folder’s file plus every parent’sWork inside one package

Our demo monorepo has a root CLAUDE.md plus one in each package. We started Claude inside packages/api, and the header confirms the working folder.

Claude Code welcome screen started inside the packages/api folder of a demo monorepo
Starting Claude Code inside one package scopes the whole session to it

One catch: project settings in .claude/settings.json are not inherited from parent folders the way CLAUDE.md files are. If you start from packages/api, Claude reads packages/api/.claude/settings.json, not the root one.

Decision diagram: start in one package if the task stays there, use --add-dir for one or two siblings, start at the repo root for changes that span many packages
A quick way to decide where to start Claude in a monorepo

Step 2: Layer CLAUDE.md Files by Folder

The common split is two levels. The root CLAUDE.md file holds rules for everyone, like commit style. Each package or subsystem gets its own CLAUDE.md for its stack.

Here are the two files from our demo:

# CLAUDE.md (repo root)
Run package scripts from the package directory, not the monorepo root.
Prefix commit subjects with the package name, for example `api: add rate limiting`.

# packages/api/CLAUDE.md
Route handlers live in src/routes.js. Keep them small and return JSON.
Never edit files in dist/. It is build output.

To check which files actually loaded, run /context and look under Memory files. When we started from the repo root, only the root file was listed.

Claude Code /context output started from the monorepo root, listing only the root CLAUDE.md under Memory files
From the repo root, /context lists just the root CLAUDE.md at launch

Then we started from packages/api. This time /context listed the root CLAUDE.md and the api CLAUDE.md, with nothing from packages/web. It also showed the api-testing skill we placed in that package.

Claude Code /context output started from packages/api, listing the root and api CLAUDE.md files plus the api-testing project skill
From packages/api, Claude loads the root and api rules and the package’s own skill

Per-folder CLAUDE.md vs path-scoped rules

You can also target rules with files in .claude/rules/ that have a paths: glob. A per-folder CLAUDE.md lives next to its code and is easy for each team to own. A path-scoped rule lives in one central place and loads when Claude works on matching files, which suits rules that apply to scattered paths.

Keep the files current

  • Review CLAUDE.md edits in pull requests, like any other docs change.
  • Revisit them after major model releases, since old workarounds can become dead weight.
  • Try a Stop hook that reviews the session transcript and proposes CLAUDE.md updates.
  • Run /doctor to trim a file that has grown too large.

Step 3: Exclude CLAUDE.md Files You Never Need

When you start from the root, package CLAUDE.md files can still load on demand as Claude moves around. The claudeMdExcludes setting skips specific files by path or glob so they never load. It is meant for folders you never touch, like another team’s package or legacy code.

{
  "claudeMdExcludes": [
    "**/packages/web/**"
  ]
}

Put that in .claude/settings.local.json if it is just for you, and add the file to your gitignore yourself. Patterns match absolute paths, so start relative-style patterns with **/. A few more useful patterns from the docs:

  • “**/packages/*/CLAUDE.md” skips every package file but keeps the root one.
  • “**/packages/legacy-*/**” skips every legacy package, rules included.
  • An absolute path skips one exact file.

The list is static. To focus on a different package tomorrow, start Claude from that package instead of editing exclusions. The arrays merge across user, project, local and managed settings, and an organization’s managed CLAUDE.md can’t be excluded.

Step 4: Block Reads of Build Output and Vendored Code

Claude’s searches already respect .gitignore, so node_modules/, dist/ and build/ stay out of search results if they are ignored. For folders that are checked in, like a vendored SDK or committed generated code, add Read deny rules. We put these in packages/api/.claude/settings.json:

{
  "permissions": {
    "additionalDirectories": [
      "../shared"
    ],
    "deny": [
      "Read(./**/dist/**/*)",
      "Read(./**/build/**/*)"
    ]
  }
}

The patterns end in /**/* on purpose. That blocks everything inside the folder but not the folder itself, so Claude can still list it. Then we asked Claude to show the first line of dist/bundle.js.

Claude Code explaining that permission settings block access to the dist directory after a Read deny rule stopped the file read
The Read deny rule stopped Claude from opening build output in dist/

Claude reported that the read was denied and did not try to sneak around it with cat.

Deny rules cover the built-in file tools and common Bash file commands like cat, head, grep and find when the denied path is an argument. They do not cover programs that open files on their own, and a broad grep -r over a folder can still show denied files. Our guide to deny rules covers the full syntax.

Which settings file should hold the deny rules?

Who should get the rulesWhere to put them
Everyone in the repo.claude/settings.json at the root, or in each package you start from
Only you.claude/settings.local.json at the repo root (use //-absolute paths if you start in subfolders)
Everyone, enforcedManaged settings, which other scopes cannot override

Step 5: Reach a Sibling Package Safely

Starting in packages/api keeps Claude inside that folder. But real work often touches a shared package too. The additionalDirectories setting above granted access to ../shared, so we asked Claude what that package exports.

Claude Code reading a file in the sibling shared package and summarizing its exports
With additionalDirectories, Claude read the shared package without leaving packages/api

Claude read the file and answered in one sentence. You can also grant access just for one session with a flag:

claude --add-dir ../shared

The two methods differ in what else loads. This table is worth remembering:

Added withLoads that folder’s CLAUDE.md and rulesLoads its skills
additionalDirectories settingNeverNever
–add-dir flag or /add-dir commandOnly with CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1Yes

Step 6: Use Sparse Worktrees for Big Repos

The –worktree flag starts Claude in a separate git worktree so changes stay away from your main checkout. By default that copies the whole repo, which is slow in a giant monorepo. The worktree.sparsePaths setting uses git sparse-checkout to write only the folders you list, plus root-level files.

We added this to the root .claude/settings.json and ran claude –worktree sparse-demo from the repo root:

{
  "worktree": {
    "sparsePaths": [
      ".claude",
      "packages/api",
      "packages/shared"
    ]
  }
}

Inside the session we ran ls packages and git sparse-checkout list with the ! shell prefix.

Claude Code session inside a sparse worktree where the packages folder contains only api and shared
The sparse worktree held only api and shared; packages/web was never checked out

Only api and shared were on disk. A few rules from the docs to keep in mind:

  • List folders, not single files. Root files like package.json always come along.
  • Include .claude if you want the root settings and rules inside the worktree.
  • Add “symlinkDirectories”: [“node_modules”] to link node_modules instead of copying it.
  • All worktrees in a session share the same sparsePaths, including subagent worktrees.

One subtle point: inside a worktree, settings load from the worktree root, not the package you launched from. So put deny rules you need there in the root .claude/settings.json. Our full git worktrees guide covers the basics.

Step 7: Add Per-Package Skills and Code Intelligence

Any folder can hold its own Claude Code skills in .claude/skills/. Our demo had an api-testing skill in packages/api, and it showed up in /context only when we started from that package. A skill loads its full content only when Claude decides it is relevant.

---
name: api-testing
description: Testing patterns for the API package. Use when writing or modifying tests in packages/api/.
---

With many skills, descriptions can get cut short, so keep them brief and lead with words a request would contain. Skills that every package shares belong in the root .claude/skills/, or in a plugin if they need version history.

For finding code, a code intelligence plugin connects Claude to a language server. It can then jump to definitions and find references instead of grepping through the tree. Install the TypeScript one from the official marketplace with:

/plugin install typescript-lsp@claude-plugins-official

Each developer also needs the language server binary installed. You can turn the plugin on for the whole repo with the enabledPlugins project setting; see our plugins guide for how installs work.

Real Examples: Changes That Span Packages

When one change touches several packages, like renaming a shared type and every call site, how you run the task matters as much as the setup. The docs recommend two habits.

  1. Give Claude the whole change in one session, so every edit follows the same decisions.
  2. Plan first in plan mode. Claude writes the plan to a file and re-injects it after each compaction, so a long session does not lose the plan.

When per-folder files stop scaling, a platform team can move conventions into skills, plugins, or an MCP server that exposes an existing code search index. A SessionStart hook can even tell Claude which plugin a folder’s owners recommend.

Try It Yourself

Make a tiny monorepo with packages/api, packages/web and packages/shared, each with a one-line CLAUDE.md. Add a dist/ folder with a fake file in packages/api, plus the settings.json from Step 4. Start Claude inside packages/api, run /context, then paste this prompt:

Without editing anything, tell me which CLAUDE.md files you loaded, then try to show the first line of dist/bundle.js, and finally summarize in one sentence what ../shared exports.

You should see the root and api rules, a denied read on dist/, and a working read of the shared package.

Common Mistakes

  • Expecting the root .claude/settings.json to apply when you start inside a package. It doesn’t; settings are not inherited.
  • Writing deny patterns as dist/** when you still want Claude to list the folder. Use /**/* instead.
  • Using additionalDirectories and wondering why the sibling’s skills never appear. Only –add-dir loads skills.
  • Forgetting .claude in sparsePaths, then finding no project settings inside the worktree.
  • Editing claudeMdExcludes every day to switch focus. Start Claude in the right folder instead.

Pro Tips

  • Run /context in each package once to confirm exactly what loads. It costs nothing.
  • Keep the root CLAUDE.md short and push stack details down into package files.
  • Pair claudeMdExcludes and Read deny rules with a code intelligence plugin for the biggest savings.
  • Run long investigations in subagents so their file reads stay out of your main conversation.
  • Check how each scope merges in our settings files guide before committing team rules.

Cheat Sheet

Cheat sheet of Claude Code commands and settings for large codebases and monorepos
The key commands and settings for running Claude Code in a monorepo

For every option and edge case, read Anthropic’s large codebases guide and the settings reference.

Frequently Asked Questions

Can Claude Code handle a repo with millions of lines?

Yes. Claude Code works at any size; the setup in this guide just keeps unrelated instructions and file reads out of its context, which saves tokens and keeps answers focused.

Should I start Claude at the repo root or in a package?

Start in the package when the task stays there. Start at the root when a change spans many packages, and plan first.

How do I see which CLAUDE.md files loaded?

Run /context and look at the Memory files list. In our test it showed one file from the root and two from packages/api.

Do Read deny rules make files fully invisible?

Not completely. They block Claude’s file tools and common Bash file commands, but a broad grep -r or a program that opens files itself can still see them.

Does worktree.sparsePaths work with subagents?

Yes. Each subagent that runs in a worktree gets the same lightweight checkout, so list every folder any of them needs.

Conclusion

A Claude Code large codebase setup comes down to scope: start Claude in the folder your task lives in, split CLAUDE.md by package, exclude what you never need, block build output, add siblings only when a task needs them, and keep worktrees sparse. In our demo monorepo, starting in packages/api loaded only the right rules and skill, a deny rule kept Claude out of dist/, the shared package was one setting away, and the worktree held just two packages. Stack the layers your repo needs and Claude AI will spend its context on your code, not on everyone else’s.

Previous in the series: Part 43, Claude Code Security: Catch Issues as Claude Writes Code

Next in the series: Part 45: How to Fix Claude Code Install and Login Problems.

Newsletter

New AI tools in your inbox

The best new tools and the AI news that matters, in one short email. Unsubscribe any time.

Free · No spam · Unsubscribe any time

✓ Looks like you’re subscribed

Loading Google’s sign-up form…

Looks like you’re already subscribed

Thanks for reading! New AI tools and the AI news that matters will land in your inbox.

Not subscribed yet? Refresh the page to load the sign-up form.

The sign-up form couldn’t load. If you use an ad or content blocker, allow news.google.com and reload the page.

Free instant check before you pay. Takes a few seconds.

Scroll to Top