If you're using Claude Code to build Next.js applications with React and TypeScript in 2026, there's one file that separates a frustrating "fix this again" loop from a genuinely productive agentic workflow: CLAUDE.md.
I've been shipping Next.js + TypeScript apps with Claude Code for months now, and the difference between a project with a well-crafted CLAUDE.md and one without is night and day. Without it, Claude mixes up App Router and Pages Router conventions, generates client components where server components belong, and ignores your data fetching patterns. With it, Claude writes code that fits your architecture like it's been pair-programming with you for weeks.
Here's exactly how I set up CLAUDE.md for my Next.js projects — and why every decision matters.
CLAUDE.md is a markdown file that lives in your project root (or at .claude/CLAUDE.md). Claude Code reads it at the start of every session and treats it as persistent context — your project's memory layer that survives session resets.
Think of it as a senior developer's onboarding doc, except the reader is an AI agent that will literally follow these instructions when generating code, running commands, and making architectural decisions. It's not configuration in the traditional sense — Claude reads it and tries to follow it, so specificity is everything.
There are three scopes where CLAUDE.md can live:
./CLAUDE.md): Team-shared instructions committed to source control. This is your primary file.~/.claude/CLAUDE.md): Personal preferences across all projects — your coding style, preferred tooling shortcuts.For a Next.js project, the project-level file is where 90% of the value sits.
After iterating on dozens of projects, here's the structure I've landed on. Each section exists for a reason — cut any of them and you'll notice Claude's output quality drop.
Start with 2–3 lines describing what the app does, who it's for, and the core tech stack. Claude uses this to make judgment calls when you're vague.
# Project Overview
This is a B2B SaaS dashboard built with Next.js 15 (App Router), React 19,
and TypeScript 5.x. Uses TanStack Query for client-side server state and
Next.js Server Actions for mutations. The backend is a .NET 9 Web API
with SQL Server. Deployed on Vercel.
Notice I included the backend stack too. Even if Claude is only touching frontend code, knowing the API layer is .NET helps it generate correct fetch calls, error handling patterns, and type definitions. And specifying "App Router" upfront prevents Claude from ever generating Pages Router code.
This is the section most developers skip — and it's the one that causes the most frustration when missing. Next.js has strong conventions around the app/ directory, but Claude still needs to know where your shared code lives.
# Project Structure
app/ # Next.js App Router — routes, layouts, pages, loading/error states
(auth)/ # Route group for authenticated pages (shared layout with sidebar)
(public)/ # Route group for public pages (marketing, login)
api/ # API route handlers (Route Handlers)
components/ # Shared UI components (atomic design: atoms, molecules, organisms)
features/ # Feature modules, each with its own components/, hooks/, types/, actions/
hooks/ # Global custom hooks
lib/ # Utility functions, API client, constants, db helpers
types/ # Shared TypeScript interfaces and type definitions
stores/ # Zustand stores for client-side global state
styles/ # Global styles, Tailwind config extensions
The comments after each directory are critical. Claude reads them to decide where new files go. Specifying route groups like (auth)/ and (public)/ means Claude will place authenticated pages in the right group without you having to remind it every time.
This section is what separates a generic React CLAUDE.md from one that actually works with Next.js. Without these rules, Claude defaults to client components for everything — throwing away half the framework's value.
# Next.js Conventions
- Default to Server Components. Only add 'use client' when the component needs hooks, event handlers, or browser APIs.
- Page components (page.tsx) are always Server Components. They fetch data directly using async/await.
- Interactive UI goes in separate Client Components imported by the Server Component page.
- Use Next.js Server Actions (in `features/{feature}/actions/`) for form submissions and mutations.
- Use `loading.tsx` and `error.tsx` files in route segments for loading/error UI — don't build custom spinners per page.
- Images always use `next/image`. Never use raw `<img>` tags.
- Internal navigation uses `next/link`. Never use `window.location` or `<a>` for internal routes.
- Use route groups `(auth)` and `(public)` to share layouts. Don't nest layouts deeper than 2 levels.
- Metadata uses the `generateMetadata` function or static `metadata` export — never `<Head>`.
The Server Component default rule alone is the single most impactful instruction in my CLAUDE.md. Before I added it, every component Claude generated started with 'use client'. Now it correctly splits server and client concerns.
This is where vague instructions kill you. "Write clean code" means nothing. Here's what actually works:
# Code Conventions
- TypeScript strict mode is ON. No `any` types unless explicitly justified with a comment.
- Use functional components with hooks. Never class components.
- Name components in PascalCase. Name hooks with `use` prefix (e.g., useAuth, useDashboardData).
- All props must have explicit TypeScript interfaces. Name them {ComponentName}Props.
- Use named exports, not default exports (except page.tsx, layout.tsx, and other Next.js conventions).
- 2-space indentation. Single quotes for strings. No semicolons (Prettier handles this).
- Prefer `const` over `let`. Never use `var`.
- Destructure props in function parameters: `function UserCard({ name, email }: UserCardProps)`
Every line here is a concrete, verifiable rule. Claude can check "did I use any?" — it can't check "did I write clean code?"
Next.js data fetching is fundamentally different from client-side React. Your CLAUDE.md needs to be explicit about when to use server-side fetching vs. client-side queries, or Claude will mix them randomly.
# Data Fetching
- Server Components fetch data directly with async/await using `lib/api.ts` helpers.
- Client Components that need real-time or interactive data use TanStack Query hooks in `features/{feature}/hooks/`.
- All query keys follow the pattern: [feature, entity, ...params] e.g., ['dashboard', 'metrics', { period }].
- Mutations use Next.js Server Actions, NOT direct API calls from the client. Actions live in `features/{feature}/actions/`.
- Server Actions must call `revalidatePath()` or `revalidateTag()` after mutating data.
- API Route Handlers (app/api/) are only for external webhooks and third-party integrations — internal data flows use Server Actions.
# State Management
- Server state in Server Components: direct fetch with async/await.
- Server state in Client Components: TanStack Query (React Query v5).
- Client state: Zustand for global UI state (theme, sidebar, modals). Keep stores in `stores/`.
- Form state: React Hook Form with Zod validation schemas. Schemas live next to the form component.
- URL state: Use `useSearchParams` for filters, pagination, sort. Don't duplicate URL state in Zustand.
The distinction between Server Actions and API Route Handlers is crucial. Before I added that rule, Claude would create unnecessary API routes for simple form submissions instead of using Server Actions.
Claude Code runs commands in your terminal. If it doesn't know your exact commands, it guesses — and guesses wrong.
# Commands
- Dev server: `pnpm dev` (Next.js, port 3000)
- Build: `pnpm build` (next build)
- Test: `pnpm test` (Vitest with React Testing Library)
- Lint: `pnpm lint` (next lint + Prettier check)
- Type check: `pnpm typecheck` (tsc --noEmit)
- Run tests before committing. Run typecheck before pushing.
That last line is a behavioral instruction — Claude will actually run pnpm test before creating a commit if you tell it to.
This section prevents the most common code quality issues I've seen Claude produce without guidance:
# Error Handling
- Use Next.js error.tsx files at route segment boundaries for error UI.
- Server Actions must return typed results: `{ success: true, data } | { success: false, error }`.
- API errors should be typed: `ApiError { status: number; message: string; code: string }`.
- Loading states: use loading.tsx for route-level, Suspense boundaries for component-level.
- All async operations in Client Components must have try/catch with typed error handling.
As your project grows, cramming everything into one CLAUDE.md gets unwieldy. Anthropic recommends keeping it under 200 lines for best adherence. Here's how I scale it.
I use .claude/rules/ with path-scoped files:
.claude/
CLAUDE.md # Core project info (under 200 lines)
rules/
server-actions.md # Rules scoped to features/**/actions/*.ts
api-hooks.md # Rules scoped to features/**/hooks/*.ts
components.md # Rules scoped to components/**/*.tsx
testing.md # Rules scoped to **/*.test.ts
Each rules file uses YAML frontmatter to specify which file paths trigger it:
---
paths:
- "features/**/actions/*.ts"
---
# Server Action Rules
- Always use 'use server' at the top of the file.
- Validate all inputs with Zod before processing.
- Return typed ActionResult<T> from every action.
- Call revalidatePath() or revalidateTag() after mutations.
These rules only load when Claude touches matching files — keeping context lean and relevant.
One trick I use heavily: importing existing project files into CLAUDE.md with the @path syntax. This way, Claude always has your API schema or component library index in context without you duplicating content.
# Reference Files
See @types/api.ts for all API response types.
See @package.json for available scripts and dependencies.
See @next.config.ts for Next.js configuration and redirects.
Claude expands these at session start, so it knows your exact API types when generating components. No more guessing field names.
Here's what changed in my workflow after investing 30 minutes in a proper CLAUDE.md:
Before: I'd ask Claude to create a user profile page. It would slap 'use client' at the top, fetch data with useEffect + fetch, dump everything in a single file under app/, and use any types for the API response. I'd spend 20 minutes refactoring into proper server/client splits.
After: Same prompt. Claude generates a Server Component page.tsx that fetches user data with async/await, a separate Client Component ProfileEditor.tsx for the interactive form, a Server Action in features/profile/actions/updateProfile.ts with Zod validation, proper types from types/, and a loading.tsx file for the route. Ready for review in under 2 minutes.
That's not a marginal improvement — it's a fundamentally different development experience.
If you're starting from zero, Claude Code has a built-in command:
claude
/init
This scans your codebase and generates a starter CLAUDE.md with build commands, directory structure, and conventions it discovers. It's a solid 60% starting point — you'll want to refine the Next.js conventions, data fetching, and server/client boundaries manually since those are where your project's personality lives.
For the interactive multi-phase flow that asks which artifacts to set up (CLAUDE.md, skills, hooks), set CLAUDE_CODE_NEW_INIT=true before running /init.
Here's the complete, production-ready CLAUDE.md I use for Next.js + React + TypeScript projects. Copy it into your project root, tweak the project overview and structure to match your app, and you're set.
# Project Overview
This is a [describe your app] built with Next.js 15 (App Router), React 19,
and TypeScript 5.x. Uses TanStack Query for client-side server state and
Next.js Server Actions for mutations. Backend is [your backend stack].
Deployed on [your platform].
# Project Structure
app/ # Next.js App Router — routes, layouts, pages, loading/error states
(auth)/ # Route group for authenticated pages
(public)/ # Route group for public pages
api/ # Route Handlers (webhooks and third-party integrations only)
components/ # Shared UI components (atoms, molecules, organisms)
features/ # Feature modules with own components/, hooks/, types/, actions/
hooks/ # Global custom hooks
lib/ # Utility functions, API client, constants
types/ # Shared TypeScript interfaces and types
stores/ # Zustand stores for client-side global state
styles/ # Global styles, Tailwind config extensions
# Next.js Conventions
- Default to Server Components. Only add 'use client' when the component
needs hooks, event handlers, or browser APIs.
- page.tsx files are always Server Components. Fetch data with async/await.
- Interactive UI goes in Client Components imported by the page.
- Server Actions in `features/{feature}/actions/` for form submissions and mutations.
- Use loading.tsx and error.tsx in route segments for loading/error states.
- Images: always `next/image`. Never raw <img> tags.
- Navigation: always `next/link`. Never window.location or <a> for internal routes.
- Use route groups (auth) and (public) to share layouts. Max 2 levels of nesting.
- Metadata: use generateMetadata or static metadata export. Never <Head>.
# Code Conventions
- TypeScript strict mode ON. No `any` unless justified with a comment.
- Functional components with hooks only. No class components.
- PascalCase for components. `use` prefix for hooks (useAuth, useDashboardData).
- All props: explicit interface named {ComponentName}Props.
- Named exports only (except page.tsx, layout.tsx, and Next.js file conventions).
- 2-space indentation. Single quotes. No semicolons (Prettier).
- Prefer const over let. Never var.
- Destructure props: `function UserCard({ name, email }: UserCardProps)`
# Data Fetching
- Server Components: fetch data directly with async/await via `lib/api.ts`.
- Client Components: TanStack Query hooks in `features/{feature}/hooks/`.
- Query keys: [feature, entity, ...params] e.g., ['dashboard', 'metrics', { period }].
- Mutations: Server Actions, NOT direct API calls. Actions call revalidatePath()
or revalidateTag() after mutating.
- API Route Handlers (app/api/): only for external webhooks/third-party integrations.
# State Management
- Server state (Server Components): direct async/await fetch.
- Server state (Client Components): TanStack Query v5.
- Client state: Zustand in `stores/` for global UI (theme, sidebar, modals).
- Form state: React Hook Form + Zod schemas (schemas next to form component).
- URL state: useSearchParams for filters, pagination, sort. Don't duplicate in Zustand.
# Commands
- Dev: `pnpm dev` (port 3000)
- Build: `pnpm build`
- Test: `pnpm test` (Vitest + React Testing Library)
- Lint: `pnpm lint` (next lint + Prettier)
- Type check: `pnpm typecheck` (tsc --noEmit)
- Run tests before committing. Run typecheck before pushing.
# Error Handling
- Route-level: error.tsx files at route segment boundaries.
- Server Actions return: { success: true, data } | { success: false, error }.
- API errors typed: ApiError { status: number; message: string; code: string }.
- Loading: loading.tsx for routes, Suspense boundaries for components.
- Client async ops: try/catch with typed error handling.
# Reference Files
See @types/api.ts for all API response types.
See @package.json for available scripts and dependencies.
See @next.config.ts for Next.js configuration.
Your CLAUDE.md is the single highest-leverage file in any AI-assisted Next.js project. Spend 30 minutes writing it properly and you'll save hours every week. Keep it under 200 lines, be brutally specific about server vs. client boundaries, use .claude/rules/ for scoped instructions, and import existing project files with @path syntax so Claude always has real context instead of guessing.
The developers who are shipping fastest with Claude Code in 2026 aren't the ones writing the best prompts — they're the ones with the best CLAUDE.md files.