The single biggest source of AI confusion in Next.js projects: the App Router vs Pages Router split.
Every model has trained on years of Pages Router patterns — getServerSideProps, getStaticProps, API routes in pages/api/. When you start a new App Router project, those patterns keep leaking in.
A CLAUDE.md file at the repo root that declares "this is an App Router project" stops that leak. Here are 13 rules that cover the failure modes most likely to appear.
Rule 1: Declare the router version explicitly
This project uses Next.js App Router (app/ directory).
Do NOT generate Pages Router patterns:
- No getServerSideProps / getStaticProps / getStaticPaths
- No pages/api/ routes
- No _app.tsx or _document.tsx
All routing lives in app/ using the file-system convention.
This is the single most important rule. Without it, AI will mix patterns from both routers.
Rule 2: Server Components are the default
All components in app/ are React Server Components by default.
Add 'use client' ONLY when the component needs:
- useState or useReducer
- useEffect or lifecycle hooks
- Browser APIs (window, document, localStorage)
- Event handlers that require client interactivity
Do not add 'use client' preemptively.
AI that learned from React codebases defaults to client components everywhere. RSC is the App Router's core performance feature — it must be intentional, not accidental.
Rule 3: Data fetching happens in Server Components
Fetch data directly in Server Components using async/await.
Do not use useEffect + fetch, SWR, or React Query for data that
can be fetched server-side.
Pass fetched data as props to Client Components that need it.
Rule 4: Server Actions own all mutations
All form submissions and data mutations use Server Actions.
Define actions with 'use server' in a separate actions.ts file
or inline in Server Components.
Do not create API routes for mutations that can use Server Actions.
Rule 5: Route Handlers replace API routes
HTTP endpoints that cannot use Server Actions (webhooks, OAuth
callbacks, third-party integrations) live in app/api/ as
route.ts files exporting GET, POST, etc. functions.
Do not use pages/api/ — that is Pages Router only.
Rule 6: Layout files handle shared UI, not pages
app/layout.tsx: root layout — HTML shell, fonts, global providers
app/[section]/layout.tsx: section-level shared UI
page.tsx: the actual page content
Do not put page content in layout.tsx.
Rule 7: Loading and error states are file conventions
loading.tsx: shown during Server Component data fetching (Suspense)
error.tsx: shown when the segment throws (must be 'use client')
not-found.tsx: shown when notFound() is called
Do not implement these as conditional renders inside page.tsx.
Rule 8: Metadata is exported from page and layout files
Export a metadata object or generateMetadata function from
page.tsx or layout.tsx for SEO.
Do not use next/head or set document.title imperatively.
Rule 9: Image and font optimization use next/image and next/font
All images: next/image with required width and height props.
All fonts: next/font (google or local) loaded in layout.tsx.
Do not import fonts in CSS or use <img> tags directly.
Rule 10: Environment variables follow the NEXT_PUBLIC_ convention
Server-only vars: no prefix — never accessible in client bundles
Client-accessible vars: NEXT_PUBLIC_ prefix required
Never access server-only vars in 'use client' components.
Rule 11: Caching is explicit, not implicit
fetch() in Server Components: use cache option explicitly
{ cache: 'no-store' } for dynamic data
{ next: { revalidate: N } } for ISR-style revalidation
default (force-cache) for static data
Do not assume fetch is cached or uncached without declaring it.
Rule 12: Parallel and intercepting routes use folder conventions
Parallel routes: @folder naming convention (e.g., @modal)
Intercepting routes: (.) (..) (...)prefix conventions
Do not implement modals or parallel UI with client-side state
when the App Router file convention handles it natively.
Rule 13: TypeScript types for App Router APIs
Page props: { params: { slug: string }, searchParams: { q: string } }
Layout props: { children: React.ReactNode, params: { ... } }
Server Action: async function action(formData: FormData)
Route Handler: (req: Request) => Response | NextResponse
Use these types — do not invent custom prop interfaces for routing.
The full CLAUDE.md block
# Next.js Project Rules (App Router)
## Router
- App Router ONLY — app/ directory
- No Pages Router patterns (no getServerSideProps, no pages/api/)
## Components
- Default: Server Components (no 'use client' unless needed)
- 'use client' only for: state, effects, browser APIs, event handlers
- Data fetching: async/await in Server Components
- Mutations: Server Actions ('use server')
## File Conventions
- loading.tsx: Suspense fallback
- error.tsx: error boundary (must be 'use client')
- not-found.tsx: notFound() handler
- layout.tsx: shared UI, NOT page content
## APIs
- HTTP endpoints: Route Handlers in app/api/ (route.ts)
- No pages/api/ routes
- Images: next/image with width + height
- Fonts: next/font in root layout
## Environment
- Server vars: no prefix
- Client vars: NEXT_PUBLIC_ prefix only
- fetch() cache: declare explicitly (no-store / revalidate / force-cache)
## Metadata
- Export metadata object or generateMetadata from page/layout
- No next/head, no document.title
Why App Router AI drift is so common
The App Router launched in Next.js 13.4 as stable. Before that, three years of Pages Router content dominated the web — tutorials, Stack Overflow answers, blog posts, training data.
Every AI model has seen far more Pages Router than App Router. Without explicit instruction, it defaults to what it knows.
The CLAUDE.md file is the explicit instruction. It doesn't require the AI to be smarter — it requires you to be clearer about what generation context you're operating in.
These 13 rules are part of a framework-specific CLAUDE.md series. The Cursor Rules Pack equivalent (50 production-tested rules across all stacks) is available at oliviacraftlat.gumroad.com/l/wyaeil — search "Olivia Craft Cursor Rules" on Gumroad.












