---
name: nextjs
description: >-
  Next.js 16+ App Router with React Server Components and TypeScript. Use when
  working in app/, layouts, pages, route handlers, proxy.ts, Server Actions,
  "use client"/"use server"/"use cache" boundaries, caching and revalidation,
  typed routes, view transitions, Cache Components adoption, instant navigation
  optimization, runtime verification, or Partial Prefetching adoption.
---

# Next.js

Reference for Next.js 16+ App Router projects. Prefer the project's existing
conventions, then steer with four leading words: **boundary**, **dynamic by
default**, **pass-through**, and **generated types**.

The adoption, optimization, and development-loop references target Next.js
16.3+. Check their prerequisites before using them on a 16.x project; an
upgrade is a separate change, not an implicit part of a runtime check.
Prefer installed-version docs in `node_modules/next/dist/docs/` (bundled since
16.2). Locate guides by filename because directory prefixes are numbered.
For earlier versions, use the matching official upgrade or API documentation.
Error pages under `/docs/messages/` must be read online.

Branch-specific references, loaded on demand:

- [boundary.md](boundary.md) — server/client split, providers, `server-only`,
  where state and files go.
- [caching.md](caching.md) — `use cache`, `cacheLife`, `updateTag` vs
  `revalidateTag`, and the traps that pass `next build`.
- [actions-and-routes.md](actions-and-routes.md) — Server Actions, Route
  Handlers, `proxy.ts`, metadata.
- [typescript.md](typescript.md) — `PageProps`/`LayoutProps`/`RouteContext`,
  `typedRoutes`, `satisfies`, discriminated unions.
- [view-transitions.md](view-transitions.md) — `<ViewTransition>`, canary-only.
- [migration.md](migration.md) — what changed from 15, renames, removals.

## First Checks

1. Locate `next.config.{js,ts,mjs,cjs}` and use its directory as the project
   root. Read `cacheComponents`, `partialPrefetching`, `typedRoutes`, and
   `experimental.*` flags. `cacheComponents` decides the caching branch.
2. Get the exact version from the lockfile. Major-version drift makes most of
   this skill's specifics wrong.
3. Locate the routing root (`app/` or `src/app/`), `proxy.ts`, and whether the
   project still has a `middleware.ts` to migrate. If both app directories
   exist, `app/` shadows `src/app/`; resolve the intended tree before migration.
4. Find existing data-fetching, auth, and error-handling conventions before
   introducing new ones.

Done when: the installed Next version is stated, the `cacheComponents` and
`partialPrefetching` states are known, and the routing root is located.

## Reach For The MCP Server

Next.js 16+ runs a built-in MCP endpoint at `/_next/mcp` inside the dev server;
the `next-devtools-mcp` package connects an agent to it. It reports real build,
runtime and type errors (`get_errors`), dev logs (`get_logs`), the route table
(`get_routes`), a page's rendering info (`get_page_metadata`), and maps a
Server Action ID back to its source (`get_server_action_by_id`).
Discover the current surface with `tools/list`; tools and prerequisites vary
by version. `get_compilation_issues` needs Turbopack.

Prefer it over guessing whenever a dev server is running: it answers from the
running app rather than from this file. It is development-time only, and its
tool list grows between releases.

Setup is `.mcp.json` at the project root:

```json
{
  "mcpServers": {
    "next-devtools": {
      "command": "npx",
      "args": ["-y", "next-devtools-mcp@latest"]
    }
  }
}
```

If tools are missing: check Next 16+, confirm the dev server is running, and
restart it if it was started before the config landed.

## Choose The Workflow

Pick the requested branch; follow its prerequisite and verification pointers
as needed. Complete its criterion before claiming the task done.

### Adoption and runtime workflows

| Task | Read before starting | Completion gate |
| --- | --- | --- |
| Enable `cacheComponents`, migrate blocking routes, or review `instant = false` | [cache-components-adoption.md](cache-components-adoption.md) | Requested adoption checkpoint verified; deferred routes distinguished from adopted routes |
| Grow a static shell or make a navigation instant | [navigation-optimization.md](navigation-optimization.md) | Meaningful shell verified by a production-mode `instant()` regression test |
| Verify edited app code while `next dev` is running | [dev-loop.md](dev-loop.md) | Framework and browser checks agree; missing checks explicitly reported |
| Enable `partialPrefetching` or preserve existing full prefetches | [partial-prefetching.md](partial-prefetching.md) | Flag-off preservation baseline and unchanged final tests pass; development insights reviewed |

These references synthesize the four official `vercel/next.js` skills at
commit `3cf1f7418ff9e3ce0f54b4c3212964e421933237`. Each links its pinned source
and the detailed recipes needed only on that branch.

### Adding or changing a component

Apply **boundary**: layouts and pages are Server Components by default;
`"use client"` marks an entry point, and every module it imports joins the
client bundle. Push the directive down to the interactive leaf.

Apply **pass-through** to escape it: Server Components handed to a Client
Component as `children` or props are not in its module graph — they render on
the server and arrive as rendered output. This is what lets state live in a
small client shell wrapped around server content.

Read [boundary.md](boundary.md) before adding a directive, a provider, or a
piece of shared state.

Done when: each new `"use client"` sits at the smallest component that needs
it, server-only modules reachable from the change import `server-only`, and
props crossing the boundary are serializable — no functions, no class
instances.

### Fetching or caching data

Apply **dynamic by default**: make caching deliberate under `cacheComponents`.
Read [caching.md](caching.md) before changing a cached scope, lifetime, tag, or
revalidation call; it owns request-data boundaries and existing-cache compatibility.

Done when: every cached scope's request-scoped inputs are read outside it and
passed in as arguments, each `use cache` has a deliberate `cacheLife` profile
or a stated reason to accept the default, and the invalidation verb matches the
need — `updateTag` for read-your-writes, `revalidateTag` with a profile
otherwise.

### Writing a Server Action or Route Handler

Read [actions-and-routes.md](actions-and-routes.md).

Done when: the action authenticates and authorizes internally, its result is a
discriminated union rather than a thrown string, and dynamic APIs (`params`,
`cookies()`, `headers()`) are awaited.

### Typing routes and boundaries

Apply **generated types**: `PageProps<'/route'>`, `LayoutProps<'/route'>` and
`RouteContext<'/route'>` are global, generated from the filesystem, and beat
hand-written param types. Regenerate with `next typegen`.

Read [typescript.md](typescript.md).

Done when: route components use the generated helpers rather than hand-written
`params` types, and type checking passes — never silenced with
`typescript.ignoreBuildErrors`.

### Animating between states or routes

Read [view-transitions.md](view-transitions.md) first — the API is React
canary, usable in the App Router only because Next bundles that channel.

Done when: the transition communicates a stated spatial relationship, it is
triggered by `startTransition`, `useDeferredValue` or `Suspense` rather than a
bare `setState`, and reduced motion is handled explicitly.

### Upgrading from Next.js 15

Read [migration.md](migration.md).

Done when: `middleware.ts` is renamed to `proxy.ts`, every dynamic API is
awaited, removed config is gone (`experimental.ppr`, `experimental.dynamicIO`,
`serverRuntimeConfig`, AMP, `next lint`), and the image defaults that flipped
are reviewed against the project's usage.

## Project Structure

Next.js is deliberately unopinionated here and names three valid strategies.
This skill standardizes on the third — **split by feature or route**:

- A feature owns its components, hooks and tests, colocated in its route
  segment. Colocation is safe: a segment is not routable until it holds a
  `page.tsx` or `route.ts`, and only what those return reaches the client.
- Shared code moves up to `src/lib/` or `src/components/ui/` only once a second
  feature needs it. `components` and `lib` carry no framework meaning.
- `_folder` (private) opts a folder out of routing — the practical reason is
  avoiding collisions with future Next.js file conventions.
- `(folder)` (route group) organizes by section, intent or team without
  touching the URL, and scopes a `layout.tsx` or `loading.tsx` to that group.

State follows the same logic: lift it to the closest common parent and no
higher, where that parent is the smallest possible Client Component. See
[boundary.md](boundary.md) for why height is expensive here specifically.

## Review Checklist

- Every `"use client"` is at a leaf that needs it, not on a layout.
- Server Components reach client shells through `children`, not imports.
- Server-only modules import `server-only`; secrets never sit in a module a
  client file can reach.
- Cached scopes take request data as arguments; none reads `cookies()`,
  `headers()` or `searchParams` transitively.
- Server Actions authenticate; none trusts its caller.
- Dynamic APIs are awaited (`params`, `searchParams`, `cookies()`, `headers()`).
- Route components use `PageProps` / `LayoutProps` / `RouteContext`.
- Independent async work runs under `Promise.all`, and each `await` sits in the
  branch that uses it rather than at the top of the component.
- Suspense boundaries exist where streaming is worth it.
- The build passes with type checking on.
- Runtime changes follow [dev-loop.md](dev-loop.md); navigation claims use the
  production-mode checks in their workflow, not the build alone.
