Claude Code CLAUDE.md Best Practices: Build Consistent AI Coding Workflows with Project Conventions and Auto Memory
Why CLAUDE.md Matters for Your Development Workflow
Claude Code reads CLAUDE.md files automatically at the start of every conversation, making them the single most powerful mechanism for ensuring consistent AI-assisted development across your team. Without proper configuration, you’ll repeatedly correct the same mistakes, re-explain coding standards, and watch Claude generate code that doesn’t match your project’s conventions.
This guide covers battle-tested patterns for structuring your CLAUDE.md files, leveraging auto memory, and enforcing coding conventions that stick.
Step 1: Understand the CLAUDE.md Hierarchy
Claude Code loads instructions from multiple CLAUDE.md files in a specific priority order:
| File Location | Scope | Use Case |
|---|---|---|
~/.claude/CLAUDE.md | Global (all projects) | Personal preferences, auth info, universal rules |
PROJECT_ROOT/CLAUDE.md | Project-wide (shared via git) | Team conventions, architecture rules, forbidden patterns |
PROJECT_ROOT/src/CLAUDE.md | Directory-scoped | Module-specific patterns and constraints |
Step 2: Structure Your Project CLAUDE.md
A well-organized CLAUDE.md follows a predictable structure. Here’s a production-ready template:
# Project: MyApp
Tech Stack
- Runtime: Node.js 20 + TypeScript 5.4
- Framework: Next.js 14 (App Router)
- Database: PostgreSQL via Prisma ORM
- Testing: Vitest + Playwright
- Package manager: pnpm
Coding Conventions
- Use named exports, never default exports
- Prefer
interface over type for object shapes
- All async functions must have explicit return types
- Use
const assertions for literal objects
- File naming: kebab-case for files, PascalCase for components
Forbidden Patterns
- NEVER use
any type — use unknown and narrow
- NEVER use
console.log in production code — use the logger from @/lib/logger
- NEVER write raw SQL — always use Prisma client
- NEVER import from
../../../ — use path aliases (@/)
- NEVER add
// eslint-disable comments without explaining why
Testing Rules
- Every new function needs a unit test
- Integration tests hit real database (no mocks for DB)
- Test files live next to source:
widget.ts → widget.test.ts
Git Workflow
- Commit messages follow Conventional Commits
- Never force-push to main or develop
Always runpnpm testbefore suggesting a commit
Step 3: Define Forbidden Patterns Explicitly
The most impactful section of any CLAUDE.md is the forbidden patterns list. Claude Code respects these as hard constraints. Be specific about **what** is forbidden and **why**:
## Forbidden Patterns
No barrel exports (index.ts re-exports)
Reason: They cause circular dependencies and slow down builds.
Instead: Import directly from the source module.
No enum keyword
Reason: Enums generate runtime code and have quirky behavior.
Instead: Use as const objects with derived types.
No relative imports crossing module boundaries
Reason: Creates tight coupling between modules.
Instead: Use @/modules/auth style path aliases.
Step 4: Configure Auto Memory for Persistent Learning
Claude Code's auto memory system stores learnings across conversations. Memory files live in ~/.claude/projects/ and are indexed by a MEMORY.md file.
Here's how memory files are structured:
---
name: testing-preferences
description: Team preferences for test structure and mocking strategy
type: feedback
---
Integration tests must hit real PostgreSQL via testcontainers.
Never mock the database layer — a prior incident showed
mock/prod divergence masked a broken migration.
Unit tests can mock external HTTP calls using msw.
The MEMORY.md index keeps pointers concise:
testing-preferences - DB testing strategy and mock rules
api-conventions - REST endpoint naming and error format
user-role - Senior backend engineer, new to frontend
Memory Types at a Glance
| Type | Purpose | Example |
|---|---|---|
user | Your role, expertise, preferences | "Senior backend dev, prefers explicit over magic" |
feedback | Corrections you've given Claude | "Don't add trailing summaries after edits" |
project | Ongoing work context, deadlines | "Feature freeze starts 2026-03-20 for v2.0 release" |
reference | External resource pointers | "Bug tracker is Linear project BACKEND" |
Add workflow shortcuts directly in CLAUDE.md so Claude knows how to validate its own work:
## Validation Commands
- Lint: `pnpm lint --fix`
- Type check: `pnpm tsc --noEmit`
- Test: `pnpm vitest run --reporter=verbose`
- Format: `pnpm prettier --write .`
Before Committing
Always run this sequence:
pnpm tsc --noEmitpnpm lintpnpm vitest runIf all pass, commit with Conventional Commits format
Pro Tips for Power Users
- Layer your CLAUDE.md files: Put shared conventions in the project root, module-specific rules in subdirectory CLAUDE.md files (e.g.,
src/api/CLAUDE.mdfor API-layer rules).- Use the feedback memory type aggressively: Every time you correct Claude, say “remember this” so it saves a feedback memory. This compounds over days into a highly personalized assistant.- Pin dependency versions in CLAUDE.md: Specify exact versions of key libraries so Claude doesn’t suggest patterns from older or newer versions.- Add example code blocks: Show Claude a 10-line example of your preferred pattern rather than describing it in prose. Claude follows examples more reliably than descriptions.- Review memory periodically: Run/memoryin Claude Code to see what’s stored. Delete outdated entries that might cause conflicting instructions.
Troubleshooting Common Issues
| Problem | Cause | Fix |
|---|---|---|
| Claude ignores CLAUDE.md rules | File not in the right directory or has syntax errors | Ensure file is named exactly CLAUDE.md (case-sensitive) and is valid Markdown |
| Conflicting instructions between files | Global and project CLAUDE.md have contradictory rules | Project-level rules override global — remove duplicates and let hierarchy work |
| Memory not persisting between sessions | Memory file missing from MEMORY.md index | Every memory file must be linked in MEMORY.md — orphaned files aren't loaded |
| Claude adds unwanted comments or docstrings | Default behavior without explicit instruction | Add to CLAUDE.md: "Don't add docstrings, comments, or type annotations to code you didn't change" |
| Old conventions still applied after update | Stale memory entries override new CLAUDE.md rules | Check memory files for outdated feedback and delete them |
Can I commit CLAUDE.md to version control for my team?
Yes, and you should. The project-level CLAUDE.md in your repository root is designed to be shared via git. This ensures every team member's Claude Code instance follows the same conventions. Keep personal preferences (auth tokens, individual workflow shortcuts) in your global ~/.claude/CLAUDE.md which stays local to your machine.
How does auto memory differ from CLAUDE.md instructions?
CLAUDE.md files are static, hand-written instructions you maintain deliberately. Auto memory is dynamic — it accumulates from your interactions across conversations. Think of CLAUDE.md as your project constitution and auto memory as case law built from real corrections. Both are loaded into context, but CLAUDE.md takes priority when they conflict. Use CLAUDE.md for stable rules and let memory handle evolving preferences and context.
What’s the maximum recommended size for a CLAUDE.md file?
Keep each CLAUDE.md file under 500 lines. Claude Code loads these into the context window, so excessively long files consume tokens that could be used for actual coding. Focus on rules that Claude frequently violates or that are impossible to infer from the codebase itself. If a convention is obvious from existing code patterns, you don’t need to document it in CLAUDE.md — Claude will pick it up from reading the source files.