Next.js Best Practices
Use the project's installed Next.js version as the source of truth. This skill is baselined against the latest stable documentation for Next.js 16.3.3, but project-local, version-matched docs take precedence.
Start With the Project's Mode
Before proposing code:
- Read
package.json, the lockfile, next.config.*, and the relevant app/ or pages/ files.
- If present, follow the Next.js-managed block in the repository's
AGENTS.md and read the matching docs in node_modules/next/dist/docs/.
- Confirm whether
cacheComponents and partialPrefetching are enabled. They materially change caching, prerendering, and <Link> behavior.
- Preserve the existing router. Do not migrate from Pages Router to App Router unless the task requests it.
- Treat canary and
experimental.* features as opt-in. Do not enable them merely because they exist in the latest docs.
For version detection, bundled docs, Turbopack defaults, and the stable-versus-experimental boundary in 16.3, read version-and-tooling.
Cache Components Mode Gate
| Mode |
Correct model |
cacheComponents absent or false |
Existing route segment options such as dynamic, revalidate, and fetchCache remain valid. Apply the project's version-matched caching docs. |
cacheComponents: true |
Data is dynamic by default. Use <Suspense> for request-time work and 'use cache' plus cacheLife/cacheTag for cached work. Remove dynamic, revalidate, and fetchCache; they fail config validation in this mode. Cache Components requires the Node.js runtime. |
cacheComponents: true, partialPrefetching: true |
Each route gets a reusable App Shell. URL-specific work using params or searchParams belongs behind <Suspense> unless a link intentionally prefetches it. Audit existing <Link prefetch={true}> calls before adopting. |
Read cache-components before changing caching mode and core-navigation before changing prefetch behavior.
Current Decision Rules
- Prefer Server Components. Add
'use client' only at the smallest boundary that needs state, effects, event handlers, or browser APIs.
- Keep secrets and privileged data access in server-only modules. Server Actions are reachable POST entry points: authenticate, authorize, and validate inside every action.
- Await
params, searchParams, cookies(), and headers() in Server Components. In Client Components, unwrap promise props with React use() where appropriate.
- Use
useActionState for action results and pending state, and useOptimistic for reversible optimistic UI.
- Use
updateTag in a Server Action for read-your-own-writes. Use revalidateTag(tag, 'max') for stale-while-revalidate.
- In 16.3, prefer
retry() in error.tsx; use stable catchError from next/error for component-level boundaries. Use reset() only when re-fetching Server Component output is intentionally unnecessary.
- Use
next/root-params only for parameters above a root layout and only from Server Components. Continue using the async params prop for ordinary dynamic segments.
- Do not tune defaults without evidence. Next.js 16.3 already enables small prefetch-response inlining, Turbopack build caching, dev caching, and memory eviction.
References
Read only the references relevant to the task.
| Topic |
Reference |
| Version authority, 16.3 changes, Turbopack, TypeScript 7 |
version-and-tooling |
| Routes, layouts, and route groups |
core-routing |
| Server and Client Component boundaries |
core-server-client-components |
| Links, App Shells, Partial Prefetching, instant navigation |
core-navigation |
| Server-side data fetching |
data-fetching-server |
| Client-side data fetching |
data-fetching-client |
| Suspense and streaming |
data-streaming |
| Server Actions, forms, validation, optimistic UI |
server-actions |
| Revalidation APIs and legacy caching mode |
caching-revalidation |
Cache Components, 'use cache', cache variants, PPR |
cache-components |
Dynamic segments, generateStaticParams, root params |
file-conventions-dynamic-routes |
Loading, route errors, catchError, not found |
file-conventions-loading-error |
| Metadata, Open Graph, JSON-LD, sitemap |
metadata-seo |
| Link, Image, Script, Font, Form, server-only |
api-components |
Verification
Use the project's package manager and existing scripts. In proportion to the change:
- Run the narrow test or type check first.
- Read
next dev or next build diagnostics; Cache Components errors offer distinct stream, cache, or block fixes with different trade-offs.
- Exercise the affected route in a real browser. Verify loading, error, navigation, and mutation states, not only compilation.
- For instant-navigation work, validate the intended click-time UI in development and add an
instant() Playwright regression test when the project already uses the 16.3 tooling.
Do not report a navigation as instant from code inspection alone: prefetching is disabled in development and the production loading shell must be inspected or tested explicitly.
1---2name: next-best-practices3description: Apply current Next.js App Router practices for routing, Server and Client Components, data access, caching, mutations, navigation, metadata, and performance. Use when implementing, reviewing, debugging, or upgrading a Next.js application. Inspect the installed Next.js version and Cache Components mode before choosing APIs; do not apply 16.3-only behavior to older projects.4---56# Next.js Best Practices78Use the project's installed Next.js version as the source of truth. This skill is baselined against the latest stable documentation for Next.js 16.3.3, but project-local, version-matched docs take precedence.910## Start With the Project's Mode1112Before proposing code:13141. Read `package.json`, the lockfile, `next.config.*`, and the relevant `app/` or `pages/` files.152. If present, follow the Next.js-managed block in the repository's `AGENTS.md` and read the matching docs in `node_modules/next/dist/docs/`.163. Confirm whether `cacheComponents` and `partialPrefetching` are enabled. They materially change caching, prerendering, and `<Link>` behavior.174. Preserve the existing router. Do not migrate from Pages Router to App Router unless the task requests it.185. Treat canary and `experimental.*` features as opt-in. Do not enable them merely because they exist in the latest docs.1920For version detection, bundled docs, Turbopack defaults, and the stable-versus-experimental boundary in 16.3, read [version-and-tooling](references/version-and-tooling.mdx).2122## Cache Components Mode Gate2324| Mode | Correct model |25|------|---------------|26| `cacheComponents` absent or `false` | Existing route segment options such as `dynamic`, `revalidate`, and `fetchCache` remain valid. Apply the project's version-matched caching docs. |27| `cacheComponents: true` | Data is dynamic by default. Use `<Suspense>` for request-time work and `'use cache'` plus `cacheLife`/`cacheTag` for cached work. Remove `dynamic`, `revalidate`, and `fetchCache`; they fail config validation in this mode. Cache Components requires the Node.js runtime. |28| `cacheComponents: true`, `partialPrefetching: true` | Each route gets a reusable App Shell. URL-specific work using `params` or `searchParams` belongs behind `<Suspense>` unless a link intentionally prefetches it. Audit existing `<Link prefetch={true}>` calls before adopting. |2930Read [cache-components](references/cache-components.mdx) before changing caching mode and [core-navigation](references/core-navigation.mdx) before changing prefetch behavior.3132## Current Decision Rules3334- Prefer Server Components. Add `'use client'` only at the smallest boundary that needs state, effects, event handlers, or browser APIs.35- Keep secrets and privileged data access in server-only modules. Server Actions are reachable POST entry points: authenticate, authorize, and validate inside every action.36- Await `params`, `searchParams`, `cookies()`, and `headers()` in Server Components. In Client Components, unwrap promise props with React `use()` where appropriate.37- Use `useActionState` for action results and pending state, and `useOptimistic` for reversible optimistic UI.38- Use `updateTag` in a Server Action for read-your-own-writes. Use `revalidateTag(tag, 'max')` for stale-while-revalidate.39- In 16.3, prefer `retry()` in `error.tsx`; use stable `catchError` from `next/error` for component-level boundaries. Use `reset()` only when re-fetching Server Component output is intentionally unnecessary.40- Use `next/root-params` only for parameters above a root layout and only from Server Components. Continue using the async `params` prop for ordinary dynamic segments.41- Do not tune defaults without evidence. Next.js 16.3 already enables small prefetch-response inlining, Turbopack build caching, dev caching, and memory eviction.4243## References4445Read only the references relevant to the task.4647| Topic | Reference |48|-------|-----------|49| Version authority, 16.3 changes, Turbopack, TypeScript 7 | [version-and-tooling](references/version-and-tooling.mdx) |50| Routes, layouts, and route groups | [core-routing](references/core-routing.mdx) |51| Server and Client Component boundaries | [core-server-client-components](references/core-server-client-components.mdx) |52| Links, App Shells, Partial Prefetching, instant navigation | [core-navigation](references/core-navigation.mdx) |53| Server-side data fetching | [data-fetching-server](references/data-fetching-server.mdx) |54| Client-side data fetching | [data-fetching-client](references/data-fetching-client.mdx) |55| Suspense and streaming | [data-streaming](references/data-streaming.mdx) |56| Server Actions, forms, validation, optimistic UI | [server-actions](references/server-actions.mdx) |57| Revalidation APIs and legacy caching mode | [caching-revalidation](references/caching-revalidation.mdx) |58| Cache Components, `'use cache'`, cache variants, PPR | [cache-components](references/cache-components.mdx) |59| Dynamic segments, `generateStaticParams`, root params | [file-conventions-dynamic-routes](references/file-conventions-dynamic-routes.mdx) |60| Loading, route errors, `catchError`, not found | [file-conventions-loading-error](references/file-conventions-loading-error.mdx) |61| Metadata, Open Graph, JSON-LD, sitemap | [metadata-seo](references/metadata-seo.mdx) |62| Link, Image, Script, Font, Form, server-only | [api-components](references/api-components.mdx) |6364## Verification6566Use the project's package manager and existing scripts. In proportion to the change:67681. Run the narrow test or type check first.692. Read `next dev` or `next build` diagnostics; Cache Components errors offer distinct stream, cache, or block fixes with different trade-offs.703. Exercise the affected route in a real browser. Verify loading, error, navigation, and mutation states, not only compilation.714. For instant-navigation work, validate the intended click-time UI in development and add an `instant()` Playwright regression test when the project already uses the 16.3 tooling.7273Do not report a navigation as instant from code inspection alone: prefetching is disabled in development and the production loading shell must be inspected or tested explicitly.