Every time you start a Claude Code session, Claude begins with zero memory of previous conversations. It does not know your project conventions, your preferred testing framework, or that one build flag that took you three hours to figure out. Unless you tell it.
That is what the memory system solves. Through CLAUDE.md files, modular rules, imports, and automatic memory, you can give Claude persistent context that survives across sessions. A well-configured memory system is the single biggest lever for improving Claude Code's output quality on your project.
Learning Objectives
- Understand the full memory hierarchy and how each layer is loaded
- Create and maintain effective CLAUDE.md files using /init and manual editing
- Organize team standards with .claude/rules/ modular rule files
- Use @imports to reference external documentation without bloating CLAUDE.md
- Leverage auto-memory for Claude's self-maintained project knowledge
What Is CLAUDE.md?
CLAUDE.md is a markdown file that gives Claude persistent context about your project. It is read automatically at the start of every session. Think of it as a briefing document: it tells Claude what your project is, how it is structured, what conventions you follow, and what pitfalls to avoid.
Without CLAUDE.md, you would repeat the same instructions every session: "We use Vitest, not Jest." "The API lives in src/api/, not src/server/." "Always run pnpm lint before committing." CLAUDE.md eliminates that repetition.
A minimal CLAUDE.md looks like this:
# My Project
## Stack
- Next.js 15 with App Router
- TypeScript strict mode
- Tailwind CSS v4
- pnpm (not npm or yarn)
## Commands
- `pnpm dev` — start dev server
- `pnpm test` — run Vitest tests
- `pnpm lint` — ESLint + Prettier check
## Conventions
- Components use named exports, not default exports
- API routes return typed responses using zod schemas
- All new features require tests before mergingClaude reads this at session start and applies it throughout the conversation. When you ask it to create a component, it will use a named export. When you ask it to run tests, it will use pnpm test.
The Memory Hierarchy
Claude Code uses a layered memory system. More specific memories take precedence over broader ones. Understanding this hierarchy is essential for organizing your instructions effectively.
| Memory Type | Location | Scope | Shared With |
|---|---|---|---|
| Managed policy | System-level (set by IT/DevOps) | All users in organization | Entire organization |
| Project memory | ./CLAUDE.md or ./.claude/CLAUDE.md | This project | Team (via source control) |
| Project rules | ./.claude/rules/*.md | This project | Team (via source control) |
| User memory | ~/.claude/CLAUDE.md | All your projects | Just you |
| Local project memory | ./CLAUDE.local.md | This project, this machine | Just you |
| Auto memory | ~/.claude/projects/<project>/memory/ | This project, this machine | Just you |
Here is how the loading works in practice:
- Parent directories first: Claude recurses upward from your current working directory to the git root, loading any CLAUDE.md or CLAUDE.local.md files it finds along the way.
- Rules directory: All
.mdfiles in.claude/rules/are loaded with the same priority as.claude/CLAUDE.md. - User-level memory:
~/.claude/CLAUDE.mdand~/.claude/rules/*.mdare loaded, but project-level instructions override them. - Auto memory: The first 200 lines of the project's
MEMORY.mdare included in the system prompt. - Child directories on demand: CLAUDE.md files nested in subdirectories below your working directory are not loaded at launch. They are included only when Claude reads files in those subdirectories.
Precedence rule
More specific instructions override more general ones. A project-level CLAUDE.md overrides your user-level ~/.claude/CLAUDE.md, and a subdirectory CLAUDE.md overrides the project root CLAUDE.md when working in that subdirectory.
Creating CLAUDE.md with /init
The fastest way to get started is the /init command. Run it inside any project:
> /init
Claude will analyze your project structure, detect your stack, and generate a starter CLAUDE.md that includes:
- Project overview: Framework, language, key dependencies
- Common commands: Build, test, lint, deploy commands detected from package.json, Makefile, or similar
- Code conventions: Patterns Claude infers from your existing code
- Architecture notes: Key directories and their purposes
Customize after generating
The /init output is a starting point, not a finished product. Always review and customize it. Add conventions that Claude cannot infer from code alone, like "we prefer composition over inheritance" or "all API changes require updating the OpenAPI spec."
The generated file can be placed at either ./CLAUDE.md (project root) or ./.claude/CLAUDE.md. Both locations are equivalent. The .claude/ directory approach keeps your project root cleaner, especially if you have many dotfiles already.
What to Put in CLAUDE.md
An effective CLAUDE.md is concise, specific, and focused on things Claude cannot infer on its own. Here is a template that covers the most valuable sections:
# Project Name
## Stack
- Framework, language, and key libraries
- Package manager (pnpm, npm, yarn, bun)
- Database and ORM if applicable
## Commands
- `npm run dev` — start development server
- `npm test` — run test suite
- `npm run lint` — check linting
- `npm run build` — production build
- `npm run db:migrate` — run database migrations
## Architecture
- `src/app/` — Next.js App Router pages and layouts
- `src/lib/` — shared utilities and business logic
- `src/components/ui/` — reusable UI primitives
- `src/components/features/` — feature-specific components
## Conventions
- Use named exports for all components
- Colocate tests next to source files (Button.tsx + Button.test.tsx)
- Use `cn()` utility for conditional Tailwind classes
- Prefer server components; add "use client" only when needed
## Patterns
- Data fetching happens in server components using async/await
- Form validation uses zod schemas shared between client and server
- Error boundaries wrap each route segment
## Gotchas
- The `LEGACY_API_URL` env var must be set even in dev (see .env.example)
- Tests fail if Redis is not running locally on port 6379
- The `payments` module uses a vendored fork of stripe-js (see src/lib/stripe/README)Keep it under 200 lines
CLAUDE.md is loaded into Claude's context window every session. A 500-line file wastes tokens and can push important context out. Aim for under 200 lines. Move detailed documentation into separate files and reference them with imports.
What NOT to put in CLAUDE.md
- Content already in your README: Claude can read your README when needed. Do not duplicate it.
- Exhaustive API documentation: Use imports to reference these instead.
- Temporary notes: Use auto-memory or CLAUDE.local.md for these.
- Obvious conventions: If your linter enforces it, you do not need to also tell Claude.
The .claude/rules Directory
For larger projects or teams, a single CLAUDE.md can become unwieldy. The .claude/rules/ directory lets you split instructions into focused, modular files:
your-project/
├── .claude/
│ ├── CLAUDE.md
│ └── rules/
│ ├── code-style.md
│ ├── testing.md
│ ├── api-design.md
│ └── frontend/
│ ├── react.md
│ └── accessibility.md
All .md files in .claude/rules/ are automatically discovered (recursively through subdirectories) and loaded with the same priority as .claude/CLAUDE.md. No configuration is needed.
Path-Specific Rules
Rules can be scoped to specific files using YAML frontmatter with a paths field. These conditional rules only activate when Claude is working with matching files:
---
paths:
- "src/api/**/*.ts"
- "src/api/**/*.test.ts"
---
# API Development Rules
- All endpoints must validate input with zod schemas
- Return standardized error responses using ApiError class
- Include JSDoc comments for OpenAPI generation
- Every endpoint needs at least one integration testRules without a paths field load unconditionally and apply to all files.
The paths field supports standard glob patterns and brace expansion:
---
paths:
- "src/components/**/*.{ts,tsx}"
- "{src,lib}/**/*.test.ts"
---When to use rules vs. CLAUDE.md
Use CLAUDE.md for project-wide context that everyone needs: stack, commands, architecture. Use .claude/rules/ for topic-specific standards that benefit from being in separate files: testing conventions, API design guidelines, accessibility requirements. Rules files are especially useful in teams where different people own different standards.
Sharing Rules Across Projects
The .claude/rules/ directory supports symlinks, so you can share common standards across multiple repositories:
# Symlink a shared rules directory
ln -s ~/company-standards/claude-rules .claude/rules/shared
# Or symlink individual files
ln -s ~/company-standards/security.md .claude/rules/security.mdYou can also create personal rules that apply to all your projects by placing them in ~/.claude/rules/:
~/.claude/rules/
├── preferences.md # Your personal coding preferences
└── workflows.md # Your preferred workflows
User-level rules load before project rules, so project-specific instructions take precedence.
Imports
CLAUDE.md files can reference external files using @path/to/file syntax. This lets you pull in detailed documentation without bloating your CLAUDE.md:
# My Project
See @README.md for project overview.
See @docs/architecture.md for system design.
See @package.json for available scripts.
## Conventions
- Follow the API design guide @docs/api-standards.md
- Git workflow documented in @docs/git-workflow.mdKey details about imports:
- Relative paths resolve relative to the file containing the import, not the working directory.
- Absolute paths and home-directory paths (
@~/...) are supported. - Imports are recursive up to 5 levels deep (imported files can import other files).
- Imports inside code blocks and code spans are ignored, so
@anthropic-ai/claude-codein a code example will not trigger an import. - The first time Claude encounters imports in a project, it shows an approval dialog. This is a one-time security confirmation.
Cross-worktree imports
If you work with multiple git worktrees, CLAUDE.local.md only exists in one. Use a home-directory import to share personal instructions across all worktrees:
# Individual Preferences
- @~/.claude/my-project-instructions.mdAuto-Memory
While CLAUDE.md contains instructions you write for Claude, auto-memory contains notes that Claude writes for itself. As Claude works on your project, it automatically saves useful context: project patterns, debugging insights, architecture notes, and your preferences.
How Auto-Memory Works
Each project gets its own memory directory at ~/.claude/projects/<project>/memory/. The <project> path is derived from the git repository root, so all subdirectories within the same repo share one memory directory.
The directory structure looks like this:
~/.claude/projects/<project>/memory/
├── MEMORY.md # Concise index (first 200 lines loaded at startup)
├── debugging.md # Detailed debugging notes
├── api-conventions.md # API design decisions
└── ... # Any other topic files Claude creates
The MEMORY.md file acts as an index. Only its first 200 lines are loaded into Claude's system prompt at session start. Claude keeps this file concise by moving detailed notes into separate topic files, which it reads on demand during sessions.
Managing Auto-Memory
You can interact with auto-memory in several ways:
- View and edit: Run
/memoryto open the file selector, which includes your auto-memory alongside CLAUDE.md files. - Ask Claude to remember something: Say "remember that we use pnpm, not npm" or "save to memory that the API tests require a local Redis instance."
- Edit directly: Auto-memory files are plain markdown. Open them in any editor.
Seeding auto-memory
At the start of a new project, you can accelerate Claude's learning by explicitly telling it to remember key facts: "Remember that this project uses a monorepo with packages in the packages/ directory, and we use Turborepo for build orchestration."
Enabling Auto-Memory
Auto-memory is being gradually rolled out. If you do not see it yet, force it on with an environment variable:
export CLAUDE_CODE_DISABLE_AUTO_MEMORY=0 # Force on (double-negative: "don't disable")
export CLAUDE_CODE_DISABLE_AUTO_MEMORY=1 # Force offCLAUDE.local.md for Personal Preferences
For project-specific preferences that should not be committed to version control, use CLAUDE.local.md in your project root. This file is automatically added to .gitignore.
Common uses:
# My local preferences
## Dev environment
- Dev server runs on port 4200 (my preference, not the default 3000)
- Local API endpoint: http://localhost:8080
- Test database: postgres://localhost:5432/myapp_test
## My workflow
- I prefer verbose test output: use --verbose flag
- Always show file paths as absolute paths
- When creating components, include Storybook storiesThis keeps personal preferences separate from team-shared instructions, avoiding merge conflicts and respecting individual workflows.
Build a Complete Memory System
intermediate20 minSet up a full memory system for an existing project (or create a test project for this exercise):
Part 1: Bootstrap with /init
- Navigate to your project directory and run
/init - Review the generated CLAUDE.md and note what Claude detected correctly and what it missed
Part 2: Customize CLAUDE.md
- Add at least three conventions Claude could not have inferred (naming patterns, architectural decisions, team agreements)
- Add a "Gotchas" section with at least two non-obvious things about the project
- Ensure the file stays under 200 lines
Part 3: Create modular rules
- Create
.claude/rules/testing.mdwith your testing conventions (framework, patterns, coverage expectations) - Create
.claude/rules/code-style.mdwith style rules your linter does not enforce - For one of these files, add a
pathsfrontmatter to scope it to specific file types
Part 4: Set up personal preferences
- Create a
CLAUDE.local.mdwith your personal development environment details (ports, local URLs, editor preferences) - Verify it is listed in
.gitignore
Part 5: Test the system
- Start a new Claude Code session and ask Claude to summarize what it knows about the project
- Verify it references information from your CLAUDE.md, rules files, and local preferences
Bonus: Create a ~/.claude/CLAUDE.md with preferences that apply to all your projects (preferred languages, general coding style, communication preferences).
Organize a Large CLAUDE.md with Imports
advanced15 minTake a CLAUDE.md that has grown too large (or imagine one) and refactor it using imports:
- Identify sections that exceed 20 lines of detailed documentation
- Extract each into its own file in a
docs/or.claude/directory - Replace the extracted content with an
@importreference - Verify the final CLAUDE.md is under 100 lines
- Start a new session and confirm Claude can still access the imported content
Example refactored CLAUDE.md:
# MyProject
## Overview
E-commerce platform built with Next.js and Stripe.
## Commands
- `pnpm dev` — dev server on port 3000
- `pnpm test` — run Vitest
- `pnpm build` — production build
## Architecture
See @docs/architecture.md for detailed system design.
## API Standards
Follow conventions in @docs/api-standards.md
## Deployment
See @docs/deployment.md for CI/CD pipeline details.
## Conventions
- Named exports for all components
- Colocate tests with source files
- Use server components by defaultKey Takeaway
CLAUDE.md is the single most impactful file you can create to improve Claude Code's output quality. It gives Claude persistent project context across sessions. Use the memory hierarchy intentionally: project CLAUDE.md for team-shared context, .claude/rules/ for modular standards, CLAUDE.local.md for personal preferences, imports for detailed documentation, and auto-memory for Claude's self-maintained knowledge. Keep CLAUDE.md concise (under 200 lines), specific ("use pnpm" not "use the right package manager"), and current. Run /init to bootstrap, then customize. A few minutes invested in memory configuration saves hours of repeated instructions.
Next Steps
With a solid memory system in place, Claude Code will produce better results from the very first message of every session. In the next lesson, we will explore Settings, Permissions & Security — how to configure settings at every scope, lock down tools with fine-grained permission rules, sandbox bash execution at the OS level, and protect credentials from accidental exposure.