Skip to content

Large Codebases & Monorepos

Claude Code works at any codebase size, but large repos and monorepos need extra configuration to keep context focused and costs controlled.


I want toUse
Load only relevant conventionsPer-directory CLAUDE.md files
Exclude irrelevant CLAUDE.md filesclaudeMdExcludes in settings
Block reads of generated/vendored codeRead deny rules in permissions.deny
Fast symbol navigation (not grep-scanning)Code intelligence plugin (LSP)
Worktrees with only needed directoriesworktree.sparsePaths
Access sibling packages--add-dir or additionalDirectories
Package-specific proceduresPer-directory skills

Start fromFile accessCLAUDE.md loaded
Repository rootEvery fileRoot only; subdirectory files load on demand
A subdirectoryThat subtree onlyThat dir + all ancestors

Project settings (.claude/settings.json) load ONLY from your starting directory — NOT inherited from parents.


monorepo/
CLAUDE.md # Root: repo-wide conventions
.claude/settings.json # Root: deny rules (for worktree sessions)
packages/
api/
CLAUDE.md # API-specific conventions
.claude/settings.json # API: worktree, additionalDirs, deny rules
.claude/skills/api-testing/SKILL.md
web/
CLAUDE.md # Frontend-specific conventions
.claude/skills/component-patterns/SKILL.md
shared/
CLAUDE.md

Root CLAUDE.md — repo-wide context:

This is a monorepo with three packages under packages/:
- packages/api: Node.js REST API with Express, TypeScript, PostgreSQL
- packages/web: React frontend with Vite, TypeScript, TailwindCSS
- packages/shared: shared TypeScript utilities used by both
Run commands from the package directory, not the monorepo root.

Per-package CLAUDE.md — package-specific context:

packages/api/CLAUDE.md
- Run tests: `npm test` (uses Vitest)
- Run dev server: `npm run dev` (port 3001)
- Database migrations: `npm run migrate`
- API routes in src/routes/. Database queries use Knex in src/db/.

When starting from packages/api/, Claude loads root CLAUDE.md + packages/api/CLAUDE.md. It does NOT load packages/web/CLAUDE.md.


For directories you never work in (other teams’ packages, legacy code):

// .claude/settings.local.json (kept local, not committed)
{
"claudeMdExcludes": [
"**/packages/admin-dashboard/**",
"**/packages/legacy-*/**"
]
}

Pattern examples:

  • "**/packages/*/CLAUDE.md" — exclude all package CLAUDE.md files, keep root
  • "**/packages/web/**" — exclude everything under web package

.gitignore patterns (like node_modules/) are already excluded from searches. For checked-in generated code:

packages/api/.claude/settings.json
{
"permissions": {
"deny": [
"Read(./**/dist/**)",
"Read(./**/build/**)",
"Read(./**/*.generated.*)",
"Read(./vendor/**)"
]
}
}

Also add to root .claude/settings.json so worktree sessions pick up the rules:

.claude/settings.json
{
"permissions": {
"deny": [
"Read(./**/dist/**)",
"Read(./**/build/**)"
]
}
}

Install LSP plugins so Claude can jump to definitions and find references instead of scanning files:

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

Available: TypeScript, Python, Go, Rust, and more.

To enable for everyone in the repo:

.claude/settings.json
{
"plugins": {
"enabled": ["typescript-lsp@claude-plugins-official"]
}
}

Sparse Worktrees (Check Out Only What You Need)

Section titled “Sparse Worktrees (Check Out Only What You Need)”

In large repos, --worktree by default checks out the entire repository. Use sparsePaths to only check out needed directories:

packages/api/.claude/settings.json
{
"worktree": {
"sparsePaths": [
".claude", // needed for settings + skills
"packages/api",
"packages/shared"
],
"symlinkDirectories": [
"node_modules" // symlink instead of duplicating
]
}
}
  • Paths are relative to repository root
  • Root-level files (package.json, tsconfig.json, lock files) always included
  • Root-level directories must be explicitly listed (including .claude)

When starting from packages/api/ and needing packages/shared/:

packages/api/.claude/settings.json
{
"permissions": {
"additionalDirectories": [
"../shared",
"../web"
]
}
}

Or at runtime:

Terminal window
claude --add-dir ../shared
Added withLoads CLAUDE.md + rulesLoads skills
additionalDirectories settingNeverNever
--add-dir flagOnly with env varYes

To also load CLAUDE.md from --add-dir directories:

Terminal window
CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1 claude --add-dir ../shared

Skills in packages/api/.claude/skills/ load only when Claude works in packages/api/:

packages/api/.claude/skills/api-testing/SKILL.md
---
name: api-testing
description: Testing patterns for the API package. Use when writing or modifying tests in packages/api/.
---
## Test structure
Tests are in src/__tests__/ mirroring src/ directory structure.
## Running tests
- All tests: `npm test`
- Single file: `npm test -- src/__tests__/routes/users.test.ts`
## Patterns
- Use supertest for HTTP assertions
- Always wrap database tests in a transaction that rolls back

Frontend skills live separately:

packages/web/.claude/skills/component-patterns/SKILL.md

Complete Example: packages/api/.claude/settings.json

Section titled “Complete Example: packages/api/.claude/settings.json”
{
"worktree": {
"sparsePaths": [
".claude",
"packages/api",
"packages/shared"
],
"symlinkDirectories": ["node_modules"]
},
"permissions": {
"additionalDirectories": ["../shared"],
"deny": [
"Read(./**/dist/**)",
"Read(./**/build/**)"
]
}
}

This gives you (when starting from packages/api/):

  • Only relevant CLAUDE.md files loaded
  • Access to packages/shared/ for cross-package edits
  • No reads of build artifacts
  • Fast sparse worktrees checking out only needed directories
  • node_modules symlinked, not duplicated

When a change touches several packages:

  1. Give Claude the whole change in one session — consistency across packages
  2. Save the plan first: claude --plan "update auth types across packages" — saves to a markdown file that survives context compaction

  • Use subagents for research (keep file reads out of main context)
  • Install code intelligence plugins (symbol lookup instead of file scanning)
  • Move workflow instructions from CLAUDE.md to skills (load on demand)
  • Use Read deny rules for generated/vendored code
  • Start from a subdirectory when working on one package
  • Use sparse worktrees for --worktree sessions
  • Trick: “Scope context like code ownership — nested CLAUDE.md per package.”
  • Show: cd into a package and watch its scoped rules load.
  • They’ll trip on: one root CLAUDE.md trying to describe 40 packages.

Learning path:41-cost-management.md · Index · ➡ 43-best-practices.md

Written by Fenil Patel