Claude Code Best Practices for CLAUDE.md Configuration: Project Setup That Maximizes AI Coding Quality
Why CLAUDE.md Is the Most Important File in Your Repository
When Claude Code opens your project, CLAUDE.md is the first thing it reads. This file shapes every subsequent interaction — how Claude Code navigates your codebase, which patterns it follows, what conventions it respects, and what mistakes it avoids.
A well-written CLAUDE.md transforms Claude Code from a generic coding assistant into a project-specific expert. It knows your tech stack, follows your naming conventions, avoids your known pitfalls, and understands your architecture decisions. A poor or missing CLAUDE.md forces Claude Code to guess — and guesses are inconsistent.
The investment is small (30-60 minutes to write) and the payoff is large (every Claude Code session for every developer on the team is more productive). This guide covers the patterns for writing CLAUDE.md files that produce consistently high-quality AI-assisted code.
The Optimal CLAUDE.md Structure
Section 1: Project Overview (What Is This?)
# Project Name Brief description of what this project does, who it serves, and its current state. ## Tech Stack - Language: TypeScript 5.3 - Runtime: Node.js 20 LTS - Framework: Next.js 14 (App Router) - Database: PostgreSQL 16 via Supabase - ORM: Drizzle ORM - Auth: Supabase Auth (email + Google OAuth) - Styling: Tailwind CSS + shadcn/ui - Testing: Vitest (unit) + Playwright (e2e) - Package Manager: pnpm 8 - Deployment: Vercel
Why this matters: Claude Code uses the tech stack to determine which APIs, patterns, and idioms are appropriate. Specifying “Next.js 14 App Router” tells it to use Server Components, not Pages Router patterns. Specifying “Drizzle ORM” tells it to use Drizzle query syntax, not Prisma.
Section 2: Directory Structure (Where Is Everything?)
## Directory Structure
src/
app/ — Next.js App Router pages and layouts
components/ — React components (organized by feature)
ui/ — shadcn/ui base components (do not modify)
features/ — Feature-specific components
layouts/ — Layout components (header, sidebar, footer)
lib/ — Shared utilities and configurations
db/ — Database client, schema, migrations
auth/ — Authentication helpers
api/ — API client functions
hooks/ — Custom React hooks
types/ — TypeScript type definitions
styles/ — Global styles and Tailwind config
tests/
unit/ — Unit tests (mirrors src/ structure)
e2e/ — Playwright end-to-end tests
fixtures/ — Test data and mocks
Why this matters: Claude Code knows where to create new files, where to find existing code, and how to import across the project. Without this, it may create files in incorrect locations or use wrong import paths.
Section 3: Code Conventions (How Do We Write Code?)
## Code Conventions ### Naming - Files: kebab-case (user-profile.tsx, not UserProfile.tsx) - Components: PascalCase (UserProfile, not userProfile) - Functions: camelCase (getUserById, not get_user_by_id) - Constants: UPPER_SNAKE_CASE (MAX_RETRY_COUNT) - Database tables: snake_case (user_profiles) - API routes: kebab-case (/api/user-profiles) ### TypeScript - Strict mode enabled — no `any` types unless unavoidable - Prefer `interface` over `type` for object shapes - Use `satisfies` for type-safe object literals - Export types from the module that owns them - Never use enums — use `as const` objects instead ### Components - Functional components only (no class components) - Use named exports, not default exports - Props interface defined above the component in the same file - Server Components by default; add 'use client' only when needed - Hooks at the top of the component, before any conditionals ### Error Handling - Use the AppError class from src/lib/errors.ts for all errors - Never swallow errors silently (no empty catch blocks) - API routes: return structured error responses, never throw unhandled - Client: show user-friendly error messages via toast ### Imports - Absolute imports from @/ (mapped to src/) - Group: 1) external packages, 2) internal @/ imports, 3) relative imports - No circular imports (enforced by ESLint rule)
Why this matters: Without explicit conventions, Claude Code uses generic best practices which may not match your team’s style. Specifying “named exports, not default” or “no enums” prevents code that is technically correct but stylistically wrong for your project.
Section 4: Common Tasks (How Do We Build Things?)
## Common Tasks ### Adding a new API endpoint 1. Create route file in src/app/api/[resource]/route.ts 2. Use the withAuth wrapper from src/lib/auth/middleware.ts 3. Validate input with zod schema (define in same file) 4. Use Drizzle for database queries 5. Return Response.json() with proper status codes 6. Add unit test in tests/unit/api/[resource].test.ts ### Adding a new database table 1. Define schema in src/lib/db/schema/[table-name].ts 2. Export from src/lib/db/schema/index.ts 3. Generate migration: pnpm db:generate 4. Apply migration: pnpm db:migrate 5. Add TypeScript type in src/types/[table-name].ts ### Adding a new page 1. Create directory in src/app/[route]/ 2. Add page.tsx (Server Component by default) 3. Add loading.tsx for loading state 4. Add error.tsx for error boundary 5. If authentication required: check session in the Server Component ### Running tests - All tests: pnpm test - Unit tests only: pnpm test:unit - E2E tests: pnpm test:e2e - Single file: pnpm test -- path/to/test.ts - Coverage: pnpm test:coverage
Why this matters: This section is the biggest time saver. Instead of Claude Code figuring out your workflow from reading the codebase, it follows documented steps. Every new endpoint, table, or page follows the same pattern.
Section 5: Important Rules (What Should We Never Do?)
## Important Rules ### DO NOT - Do not modify files in src/components/ui/ (these are shadcn/ui generated) - Do not use raw SQL — always use Drizzle ORM - Do not add new npm packages without discussion - Do not modify the authentication flow without security review - Do not commit .env files or any secrets - Do not use `console.log` in production code (use the logger) - Do not create God components (>300 lines = time to split) ### ALWAYS - Always run `pnpm lint` before considering work complete - Always add tests for new business logic - Always use the existing error handling pattern - Always check for existing utility functions before creating new ones - Always validate user input at the API boundary
Why this matters: Negative rules prevent Claude Code’s most common mistakes. “Do not modify shadcn/ui files” prevents it from editing generated component internals. “Do not use raw SQL” keeps it consistent with Drizzle. These rules are things you would tell a new team member on day one.
Section 6: Known Issues and Context (What Should We Know?)
## Known Issues - The search feature uses client-side filtering (TODO: move to server-side with database full-text search when we have >10K records) - The PDF export sometimes fails for reports >50 pages (known browser memory limitation — no fix needed yet) - Rate limiting is implemented but set very high (1000 req/min) — tighten before production launch ## Current Focus - We are currently building the reporting module (src/app/reports/) - The dashboard is stable — avoid unnecessary changes - Authentication is being migrated from custom JWT to Supabase Auth (migration in progress — some files have both patterns)
Why this matters: Context prevents Claude Code from “fixing” things that are intentional, or from building on patterns that are being deprecated.
Advanced CLAUDE.md Patterns
Per-Directory CLAUDE.md Files
For monorepos or large projects, add CLAUDE.md files to subdirectories:
packages/
api/
CLAUDE.md — API-specific conventions and patterns
web/
CLAUDE.md — Frontend-specific conventions
shared/
CLAUDE.md — Shared library rules
Claude Code reads the nearest CLAUDE.md when working in a directory, giving context-specific guidance.
Linking to Examples
Instead of describing a pattern in words, point to an example:
## Patterns - For API route implementation, follow the pattern in: src/app/api/users/route.ts (this is our reference implementation) - For database queries with pagination, see: src/lib/db/queries/list-with-pagination.ts - For form components with validation, see: src/components/features/user/user-edit-form.tsx
Claude Code reads the referenced file and follows its patterns exactly.
Environment-Specific Notes
## Development Setup - Copy .env.example to .env.local - Run `pnpm db:seed` for test data - Local Supabase: `npx supabase start` - Dev server: `pnpm dev` (runs on port 3000) ## CI/CD - GitHub Actions runs on every PR: lint + typecheck + unit tests - E2E tests run on merge to main - Auto-deploy to Vercel on merge to main - Preview deployments for every PR
Common CLAUDE.md Mistakes
Mistake 1: Too Long (Nobody Reads 5,000 Words)
CLAUDE.md should be 300-800 words. If you are writing more than 1,000 words, some of that content should move to per-directory CLAUDE.md files or to regular documentation.
Mistake 2: Too Generic
BAD: "Follow best practices for TypeScript" (What does this mean specifically?) GOOD: "Use strict TypeScript. No `any` types. Prefer `interface` over `type` for objects. Use `satisfies` for type-safe object literals."
Mistake 3: Outdated Information
A CLAUDE.md that references a deprecated pattern is worse than no CLAUDE.md — it actively misleads. Review and update CLAUDE.md when:
- The tech stack changes
- Major refactoring occurs
- New conventions are established
- Old patterns are deprecated
Mistake 4: Missing the “Don’t” Section
Positive instructions (“do X”) are important. Negative instructions (“do NOT Y”) are often more important — they prevent the mistakes that are hardest to catch in review.
Mistake 5: Not Specifying Build and Test Commands
If Claude Code does not know how to run your tests, it cannot verify its own work. Always include build, test, and lint commands.
Measuring CLAUDE.md Effectiveness
Before and After Comparison
Track these metrics after adding or improving CLAUDE.md:
- Code review rejection rate: how often does AI-generated code fail review?
- Convention violations: how many style/pattern issues per PR?
- Rework requests: how often does Claude Code need to redo work?
- Onboarding time: how quickly can a new developer start contributing using Claude Code?
The Litmus Test
Ask a new team member (or imagine one) to read only CLAUDE.md. Could they:
- Understand what the project does?
- Navigate the codebase confidently?
- Create a new feature following the established patterns?
- Know what NOT to do?
If yes: your CLAUDE.md is effective. If no: it needs more detail.
Frequently Asked Questions
Should every project have a CLAUDE.md?
Any project where Claude Code is used should have one. Even a minimal CLAUDE.md (tech stack + directory structure + 5 rules) dramatically improves output quality.
Can I use .cursorrules or .github/copilot-instructions.md instead?
Claude Code reads CLAUDE.md specifically. You can maintain both CLAUDE.md (for Claude Code) and other configuration files (for Cursor, Copilot) if your team uses multiple tools. The content will overlap significantly.
Should CLAUDE.md be committed to the repository?
Yes. It benefits every developer who uses Claude Code on the project. It also serves as lightweight project documentation for humans.
How often should I update CLAUDE.md?
Review monthly or whenever the tech stack, architecture, or conventions change significantly. Add new rules when you notice Claude Code making a recurring mistake — the mistake means the CLAUDE.md is missing guidance.
What is the ideal length?
300-800 words for the root CLAUDE.md. If your project needs more, split into per-directory files. The goal is not comprehensive documentation — it is the most important context that shapes every interaction.
Does the format matter?
Use markdown headers for structure. Use code blocks for file paths and commands. Use bullet points for lists. Claude Code parses markdown, so well-structured CLAUDE.md produces better results than a wall of text.