# How CLAUDE.md Loading Works with Ancestor and Descendant Files in Monorepos

> Understand CLAUDE.md loading in monorepos. Learn how ancestor files load automatically while descendant files load on-demand, optimizing your workflow.

- Repository: [Shayan Rais/claude-code-best-practice](https://github.com/shanraisshan/claude-code-best-practice)
- Tags: internals
- Published: 2026-03-12

---

**Claude Code automatically loads CLAUDE.md files by walking upward from your current directory to the filesystem root, while files in descendant directories are only loaded on-demand when you open files within them.**

This article explains the hierarchical loading mechanism implemented in the `shanraisshan/claude-code-best-practice` repository, detailing how ancestor and descendant CLAUDE.md files are handled differently to optimize context window usage in large monorepos.

## Understanding CLAUDE.md Loading Hierarchy

Claude Code implements a directional loading strategy that distinguishes between files above and below your current working directory. This design ensures repository-wide conventions are always available while keeping component-specific instructions scoped to their relevant contexts.

### Ancestor Files (Always Loaded)

When you start a Claude Code session, the tool immediately performs an **upward filesystem walk** from your current working directory to the root, collecting every CLAUDE.md file encountered along the path. This "ancestor loading" guarantees that root-level conventions are present before any user code is examined.

For example, if you launch Claude Code inside `<repo>/frontend`, the loading sequence is:

1. `<repo>/CLAUDE.md` (repository-wide conventions)
2. `<repo>/frontend/CLAUDE.md` (frontend-specific rules)

According to the source analysis in [`best-practice/claude-memory.md`](https://github.com/shanraisshan/claude-code-best-practice/blob/main/best-practice/claude-memory.md) (lines 32-40), this ancestor walk happens synchronously at session startup, ensuring foundational context is never missing.

### Descendant Files (Lazy Loaded)

Files located **below** your launch directory are not read at startup. Instead, Claude Code implements **lazy loading** for descendant CLAUDE.md files, pulling them into context only when you explicitly open or edit a file residing in that subdirectory.

This optimization keeps the initial prompt small and prevents unrelated component-specific instructions from cluttering your session. As documented in [`best-practice/claude-memory.md`](https://github.com/shanraisshan/claude-code-best-practice/blob/main/best-practice/claude-memory.md) (lines 91-95), the loading trigger occurs at file access time, not directory navigation time.

### Sibling Files (Never Loaded)

When working in `frontend/`, CLAUDE.md files in sibling directories like `backend/` or `api/` remain completely isolated. Claude Code never automatically loads instructions from parallel directory branches, ensuring that component-specific rules do not leak across unrelated parts of the monorepo.

## Global and Additional CLAUDE.md Sources

Beyond the hierarchical project loading, Claude Code supports user-wide configuration and opt-in additional directory scanning.

### User-Wide Global Configuration

A global CLAUDE.md file located at `~/.claude/CLAUDE.md` is **always injected** into every session, regardless of the project tree structure. This file serves as the top-most ancestor in the filesystem walk and therefore appears first in the prompt, making it ideal for user-specific preferences that apply across all repositories.

### Enabling Extra-Directory Loading

By default, Claude Code strictly adheres to the ancestor-only loading pattern. However, you can force the tool to also load CLAUDE.md files from non-ancestor directories (such as shared `libs/` folders) by setting the environment variable:

```bash
export CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1

```

This flag is documented in [`best-practice/claude-cli-startup-flags.md`](https://github.com/shanraisshan/claude-code-best-practice/blob/main/best-practice/claude-cli-startup-flags.md) (line 213) and overrides the default scoping behavior for specialized monorepo layouts.

## Monitoring CLAUDE.md Loading Events

Claude Code exposes the `InstructionsLoaded` hook, which fires whenever any CLAUDE.md or `.claude/rules/*.md` file is read into context. This allows automated agents or custom scripts to react to context changes, such as refreshing cached knowledge when new instructions are lazy-loaded.

The hook definition resides in [`.claude/hooks/HOOKS-README.md`](https://github.com/shanraisshan/claude-code-best-practice/blob/main/.claude/hooks/HOOKS-README.md) (lines 27-38). You can subscribe to this event by creating a hook configuration:

```yaml

# .claude/hooks/my-hook.yaml

event: InstructionsLoaded
action: |
  echo "New CLAUDE.md loaded: ${FILE_PATH}"

```

This mechanism confirms whether lazy loading is functioning as expected by logging each file as it enters the context window.

## Practical Example: Monorepo Structure

Consider the following project layout:

```text
my-monorepo/
├─ CLAUDE.md                # Repository-wide conventions (ancestor)

├─ frontend/
│   ├─ CLAUDE.md            # Frontend-specific rules (ancestor when cwd=frontend)

│   └─ src/
│       └─ App.tsx
├─ backend/
│   ├─ CLAUDE.md            # Backend-specific rules (descendant, lazy)

│   └─ src/
│       └─ server.py

```

**Scenario 1: Launching in frontend**

```bash
$ cd my-monorepo/frontend
$ claude-code start

```

Loaded immediately:
- [`my-monorepo/CLAUDE.md`](https://github.com/shanraisshan/claude-code-best-practice/blob/main/my-monorepo/CLAUDE.md)
- [`my-monorepo/frontend/CLAUDE.md`](https://github.com/shanraisshan/claude-code-best-practice/blob/main/my-monorepo/frontend/CLAUDE.md)

**Scenario 2: Opening a backend file later**

```bash
$ claude-code open ../backend/src/server.py

```

Lazy-loaded at this moment:
- [`my-monorepo/backend/CLAUDE.md`](https://github.com/shanraisshan/claude-code-best-practice/blob/main/my-monorepo/backend/CLAUDE.md)

The backend instructions were not present in the initial context, preserving prompt space until actually needed.

## Summary

- **Ancestor CLAUDE.md files** (walking upward to root) load automatically at session startup, ensuring repository-wide conventions are always present.
- **Descendant CLAUDE.md files** load lazily only when you open files within their directories, optimizing context window usage.
- **Sibling directories** never automatically share CLAUDE.md content, preventing rule leakage across monorepo components.
- **Global configuration** at `~/.claude/CLAUDE.md` applies to every session as the top-most ancestor.
- The `InstructionsLoaded` hook allows monitoring of loading events for debugging or automation purposes.

## Frequently Asked Questions

### What is the difference between ancestor and descendant CLAUDE.md loading?

Ancestor loading refers to the automatic upward filesystem walk from your current directory to the root, which happens immediately when Claude Code starts. This ensures all parent-level CLAUDE.md files are present in the initial context. Descendant loading is lazy, occurring only when you explicitly open or edit files in subdirectories, which keeps the startup prompt minimal and prevents unrelated component instructions from consuming context space.

### How do I ensure my monorepo root CLAUDE.md is always loaded?

Launch Claude Code from any subdirectory within your repository. The tool automatically walks upward to the filesystem root, collecting every CLAUDE.md file along the path, including the repository root. As long as your root CLAUDE.md exists and you start the session from within the repository tree (even deep in a frontend or backend folder), the root conventions will be loaded first.

### Can I force Claude Code to load CLAUDE.md files from sibling directories?

By default, sibling directories are isolated and their CLAUDE.md files remain unloaded. However, you can enable cross-directory loading by setting the environment variable `CLAUDE_CODE_ADDITIONAL_DIRECTORIES_CLAUDE_MD=1` before starting Claude Code. This flag overrides the strict ancestor-only behavior and allows loading from non-ancestor paths such as shared library folders, though it should be used sparingly to avoid context pollution.

### How can I verify which CLAUDE.md files are currently loaded in my session?

You can monitor loading events by subscribing to the `InstructionsLoaded` hook. Create a hook configuration file in `.claude/hooks/` that listens for this event and logs the `FILE_PATH` variable. Each time a CLAUDE.md file is loaded—whether at startup (ancestors) or lazily (descendants)—the hook fires, allowing you to see exactly which instruction files are present in your context at any given time.