# Next.js App Router

You are working in a Next.js 16 App Router project with React 19 and TypeScript. Write code for the version in `package.json`, not the one in your training data: much of what you remember from Next.js 13 to 15 has changed.

## Before you write code

- Read the version-matched docs in `node_modules/next/dist/docs/` (Next.js 16.2 and later ship them) before using an API you are not sure of. `01-app/03-api-reference/` holds the exact signatures; heed deprecation notes.
- Check `next.config.ts` for `cacheComponents`, `partialPrefetching` and `typedRoutes`: they change how pages render, cache and type their links.
- With `next dev` running, its MCP endpoint (`/_next/mcp`) reports compilation issues and errors per route. Prefer it to a full `next build` while you iterate.

## Project shape

- Routes live in `app/` (or `src/app/`). Only `page.tsx` and `route.ts` are public; colocate private files in `_folders`, group without changing the URL with `(groups)`.
- One `proxy.ts` at the root replaces `middleware.ts` (renamed in Next.js 16). Export `function proxy(request: NextRequest)` and a `config.matcher`. It runs on Node.js; use it for redirects, rewrites and headers, never for slow data fetching or as your only auth check.
- Server-only modules (database, secrets, the session) start with `import "server-only"`. Only that data access layer reads `process.env` secrets.
- Type page and layout props with the generated global helpers: `PageProps<"/blog/[slug]">`, `LayoutProps<"/dashboard">`, `RouteContext<"/api/items/[id]">`. They come from `next typegen`, `next dev` or `next build`.

## Server and Client Components

- Components are Server Components by default. Add `"use client"` only to the leaf that needs state, effects, event handlers or browser APIs, never to a page or layout just to make an error go away.
- Pass Server Components into Client Components as `children` or props instead of importing them there.
- Props crossing to the client must be serializable: no functions (except Server Functions), class instances or Dates you rely on as objects.
- Context providers are Client Components rendered as deep as possible, wrapping `{children}`.
- Read data in Server Components: `await` a query or `fetch` directly in the component. No `useEffect` fetching, no API route the same app then calls from its own server.
- Wrap shared reads in React's `cache()` so a layout and a page asking for the same user hit the database once.

## Request APIs are async

`params`, `searchParams`, `cookies()`, `headers()` and `draftMode()` return promises. Always `await` them in Server Components (or read them with `use()` in a Client Component).

```tsx
export default async function Page(props: PageProps<"/blog/[slug]">) {
  const { slug } = await props.params;
  const post = await getPost(slug);
  if (!post) notFound();
  return <Article post={post} />;
}
```

## Caching with Cache Components

When `cacheComponents: true` is set (the default for new apps), nothing is cached unless you say so, and every page is prerendered into a static shell:

- Mark cached work with the `"use cache"` directive at the top of an async function, component or page, and pair it with `cacheLife("hours" | "days" | "max" | …)` from `next/cache`. Arguments and captured values become the cache key.
- Tag what a mutation will invalidate: ``cacheTag("posts", `post-${id}`)``.
- Uncached reads (`fetch` without cache, the database, `cookies()`, `headers()`, `searchParams`) must sit inside a `<Suspense>` boundary with a real fallback; otherwise the dev overlay reports a blocking route. The fallback ships in the static shell and the content streams in.
- Read request data outside the cached scope and pass the value in as an argument. Use `"use cache: private"` only for results that must read cookies or headers themselves, and `"use cache: remote"` for a durable shared cache.
- Before reading `new Date()`, `Math.random()` or `crypto.randomUUID()` in a Server Component, either cache it or `await io()` (from `next/cache`) inside a Suspense boundary.
- Do not use `export const dynamic`, `revalidate` or `fetchCache` segment options, `unstable_cache` or `unstable_noStore` in a Cache Components app: they belong to the previous model. If `cacheComponents` is off, follow the previous model's docs instead and do not mix the two.

## Mutations: Server Functions

- Write mutations as Server Functions in a `"use server"` file (`app/actions.ts`) or inline in a Server Component. They are public HTTP endpoints: validate every input with a schema (Zod), check the session and authorize the user inside each one.
- Call them from a `<form action={…}>` first, so forms work before JavaScript loads; use `useActionState` for pending state and returned errors, `useFormStatus` in a submit button, `useOptimistic` for instant feedback.
- Return expected errors as values (`{ ok: false, errors }`); throw only for bugs.
- After a write: `updateTag(tag)` when the user must see their own change at once (Server Functions only), `revalidateTag(tag, "max")` for stale-while-revalidate (the profile argument is required since Next.js 16), `revalidatePath` for a whole route, `refresh()` to refresh the client router without invalidating data, `redirect()` last, outside `try`/`catch`.
- Route Handlers (`app/api/**/route.ts`) are for webhooks, streaming responses and clients outside your app, not for your own pages' data.

## Routing and navigation

- Use `<Link>` for internal navigation and `next/navigation` (`useRouter`, `usePathname`, `useSearchParams`) in Client Components. `useSearchParams` needs a `<Suspense>` boundary above it.
- Each segment can have `loading.tsx`, `error.tsx` (a Client Component receiving `error` and `retry`) and `not-found.tsx`. Call `notFound()` and `redirect()` from Server Components and Server Functions (`forbidden()` and `unauthorized()` need `experimental.authInterrupts`).
- For an error boundary around one component rather than a route, use `catchError` from `next/error` instead of writing a class boundary.
- Parallel route slots need a `default.tsx`.
- Prerender known dynamic segments with `generateStaticParams`.

## Metadata and assets

- Export `metadata` or `generateMetadata` from layouts and pages; set `metadataBase` once in the root layout. Use `opengraph-image.tsx`, `icon.tsx`, `sitemap.ts` and `robots.ts` file conventions instead of hand-written tags.
- Use `next/image` with `width` and `height` (or `fill` and `sizes`) and remote patterns in `images.remotePatterns` (`images.domains` is deprecated); use `next/font` for fonts, applied once on `<html>`.
- Load third-party scripts with `next/script`, never a raw `<script>` in a component.

## Config and tooling

- Turbopack is the default for `next dev` and `next build`; its options live under `turbopack` in `next.config.ts`. Do not add a webpack config unless the project already has one.
- `next lint` was removed: run ESLint or Biome directly as the project's scripts do.
- Environment variables exposed to the browser start with `NEXT_PUBLIC_` and are inlined at build time; everything else stays on the server.

## Do not

- Do not write `getServerSideProps`, `getStaticProps`, `next/router` or `pages/` APIs in an App Router project.
- Do not read `params` or `searchParams` synchronously, or call `revalidateTag` with one argument.
- Do not fetch your own Route Handlers from Server Components, or pass secrets and whole database rows to Client Components.
- Do not add `"use client"` to a layout, put `async` on a Client Component, or call `redirect()` inside `try`.

## Before you finish

- Run the type checker (`tsc --noEmit` or the project's typecheck script) and the linter, and fix what they report.
- Check the dev overlay or `/_next/mcp` for blocking-route and hydration issues on every page you touched.
- Say which routes are prerendered, cached or streamed when you change caching, so the reviewer knows what to test.
