VVersions.dev

Next.js 15 → Next.js 16

Next.js 15 to 16 is a single, well-supported step. The work concentrates in the now fully-removed synchronous request APIs, Turbopack-by-default, the middleware-to-proxy rename, and the new revalidateTag(tag, profile) signature — much of it automated by the @next/codemod upgrade CLI.

Version upgradeDifficulty: moderateEffort: 0.5–3 daysmedium risk

Last verified · Updated May 22, 2026

Migrating from Next.js 15 to Next.js 16. This is a single major step focused on the fully-removed sync request APIs, Turbopack as the default bundler, the middleware-to-proxy rename, the new revalidateTag(tag, profile) signature, and a Node.js 20.9+ floor. The @next/codemod upgrade CLI automates most of the mechanical migration.

Should you upgrade directly?

Yes. Next.js 15 → 16 is a single, well-supported step with no intermediate stop. The biggest behavioral shift is that synchronous request-API access — which merely warned in 15 — is removed entirely in 16, so make sure that audit is complete before bumping.

Key differences

  • Sync request APIs removed: await cookies/headers/draftMode/params/searchParams everywhere (the 15 warning shim is gone).
  • Turbopack is the default bundler; next build fails on a detected webpack config unless you pass --webpack.
  • middleware.ts → proxy.ts (Node.js runtime only); rename the function and skipMiddleware config flags too.
  • revalidateTag(tag) errors in TS — pass a cacheLife profile, or use the new updateTag()/refresh() APIs.
  • Minimums rise to Node.js 20.9+, TypeScript 5.1+, React 19.2.
  • Removed: AMP, next lint, serverRuntimeConfig/publicRuntimeConfig, devIndicators options, experimental ppr/dynamicIO/useCache, unstable_rootParams; parallel-route slots need default.js.
  • next/image config defaults changed (minimumCacheTTL, qualities, imageSizes, local-IP, redirects).

⚠ Finish the async request-API migration first

In 15 the synchronous shim let sync access slide with a dev warning. In 16 it is removed, so any straggler will break the build or runtime. Audit and await all of cookies/headers/draftMode/params/searchParams before you bump, and run npx next typegen for the type helpers.

Files and patterns to inspect

  • Pages/layouts/routes still reading params or searchParams synchronously.
  • Server code calling cookies(), headers(), or draftMode() without await.
  • A middleware.ts/middleware.js file and skipMiddlewareUrlNormalize-style config flags.
  • A custom webpack config in next.config (Turbopack is the default in 16).
  • revalidateTag() calls and unstable_cacheLife/unstable_cacheTag imports.
  • Parallel-route @slot directories missing default.js.
  • AMP, next lint, serverRuntimeConfig/publicRuntimeConfig, experimental.ppr/dynamicIO usage.
  • next/image config and local image src using query strings.

Next.js 15 vs Next.js 16

ConcernNext.js 15Next.js 16
Sync cookies()/headers()/paramsWarns (temporarily allowed)Removed — must await
Default bundlerwebpack (Turbopack via --turbopack)Turbopack (opt out --webpack)
Request interceptionmiddleware.tsproxy.ts (Node.js only)
revalidateTag()revalidateTag(tag)revalidateTag(tag, profile)
Minimum Node.js18.18+20.9+
React (App Router)1919.2

AI-assisted migration workflow

Migrate this app from Next.js 15 to 16. Confirm Node 20.9+ and TypeScript 5.1+, audit for any remaining sync request-API access, a middleware file, a custom webpack config, and single-argument revalidateTag() calls. Run `npx @next/codemod@canary upgrade latest` and `npx next typegen`, await all request APIs, finish the middleware-to-proxy rename, move experimental.turbopack to top-level, add cacheLife profiles to revalidateTag() (or switch to updateTag), add default.js to parallel-route slots, and remove AMP/runtime-config/devIndicators/ppr usage. Run typecheck, lint, build, and tests after each step and report before continuing.

Safety: Incremental edits only. Keep middleware (not proxy) if you require the edge runtime, and fall back to --webpack rather than reverting if a dependency blocks Turbopack.

Pre-migration checklist

  • Green test suite and successful next build on Next.js 15
  • All synchronous request-API access already awaited (it only warned in 15)
  • Node.js bumped to 20.9+ and TypeScript to 5.1+
  • Lockfile committed; dependencies audited for Turbopack and React 19.2 support
  • A dedicated upgrade branch

Rollback strategy

  • Keep the dependency bump, codemod, proxy rename, and manual fixes in separate commits.
  • Fall back to next build --webpack if a dependency blocks the Turbopack default rather than reverting the whole upgrade.
  • Revert to the prior next/react/react-dom versions and reinstall if a blocking incompatibility appears.

Official sources

Copy-ready AI prompts

Structured prompts for an AI coding assistant. Inspect first, then execute incrementally, and keep a human in the review loop.

Repo inspection: Repo inspection prompt (Next.js 16)

You are helping migrate a Next.js codebase from nextjs-15 to nextjs-16.

Do not edit files yet. First inspect the repository and report:
1. The exact next, react, and react-dom versions in package.json and the lockfile, plus the Node.js version (16 requires Node 20.9+) and TypeScript version (requires 5.1+).
2. Any remaining synchronous access to cookies(), headers(), draftMode(), params, or searchParams — these are FULLY removed in 16 and must be awaited. Also check params/id in opengraph-image/twitter-image/icon/apple-icon/sitemap generators.
3. A middleware.ts/middleware.js file and any config flags like skipMiddlewareUrlNormalize (these become proxy.ts and skipProxyUrlNormalize; note that proxy does not support the edge runtime).
4. A custom webpack config in next.config (Turbopack is the default in 16 and next build fails if a webpack config is detected) and any experimental.turbopack config to move to top-level.
5. revalidateTag() calls (now require a cacheLife profile second argument), and any unstable_cacheLife/unstable_cacheTag imports.
6. Usage of removed features: AMP (useAmp/next/amp/amp config), next lint, serverRuntimeConfig/publicRuntimeConfig, devIndicators.appIsrStatus/buildActivity, experimental.ppr/dynamicIO/useCache, unstable_rootParams, parallel-route slots missing default.js.
7. next/image config (minimumCacheTTL, qualities, imageSizes, domains) and any local image src using query strings.
8. The build, lint, and test commands.

Return: a migration risk summary, the files most likely to break, a suggested migration order, the commands to run before editing, and any questions that need human confirmation.

Safety: Inspection only. The agent must not modify files in this step.

Works with Claude Code, Cursor, GitHub Copilot.

Migration execution: Migration execution prompt (Next.js 16)

Migrate this codebase from nextjs-15 to nextjs-16, one concern at a time.

Work in this order and pause for review after each: (1) confirm Node 20.9+ and TypeScript 5.1+, then bump next, react, and react-dom to latest, (2) run the official upgrade codemod (npx @next/codemod@canary upgrade latest), which updates the turbopack config, migrates next lint to the ESLint CLI, renames middleware to proxy, removes unstable_ prefixes, and drops experimental_ppr, (3) await every remaining synchronous request API (cookies/headers/draftMode/params/searchParams) — sync access is fully removed in 16; run `npx next typegen` for PageProps/LayoutProps/RouteContext helpers, (4) finish the middleware to proxy rename (function name + config flags) unless you must keep the edge runtime, (5) handle Turbopack as default — remove --turbopack from scripts, move experimental.turbopack to top-level turbopack, and only add --webpack if you must keep a webpack build, (6) add a cacheLife profile to revalidateTag() calls (or switch to updateTag in Server Actions), (7) fix removed config (AMP, runtime config, devIndicators, ppr/dynamicIO) and add default.js to parallel-route slots, (8) review next/image config defaults, (9) fix type errors.

After each step run the project's typecheck, lint, build, and tests, and report results before continuing. Do not refactor unrelated code.

Safety: Apply changes incrementally and keep each step reviewable. Never bundle unrelated refactors.

Works with Claude Code, Cursor, GitHub Copilot.

Test plan

Commands

  • node -v # must be >= 20.9.0
  • npx tsc --noEmit
  • npm run lint
  • npm test -- --watch=false
  • npm run build

Manual checks

  • Dynamic routes: load pages reading params/searchParams and confirm they await cleanly (sync access no longer compiles/runs).
  • Auth/session: exercise routes using cookies() and headers() after awaiting them.
  • Proxy: confirm renamed proxy.ts runs request interception identically to the old middleware (note: Node.js runtime only).
  • Bundler: run next build with Turbopack (the default) and confirm output is correct; verify --webpack only if you intentionally kept webpack.
  • Caching: confirm revalidateTag()/updateTag() invalidation behaves as intended after adding cacheLife profiles.
  • Parallel routes: every @slot has a default.js and the build no longer fails.
  • Images: spot-check next/image rendering given the new qualities/minimumCacheTTL/imageSizes defaults.

Regression risks

  • Synchronous request-API access that compiled with a warning in 15 now hard-failing in 16.
  • next build failing because a dependency injects a webpack config under Turbopack-by-default.
  • Request interception silently broken if proxy.ts is created but the edge runtime was actually required.
  • Stale caches because revalidateTag() lost its single-argument behavior and needs a cacheLife profile.
  • Builds failing on parallel-route slots that lack default.js.

Acceptance criteria

  • Typecheck, lint, tests, and next build (Turbopack) all pass on Node 20.9+.
  • No synchronous request-API access remains anywhere in the app.
  • middleware is renamed to proxy (or intentionally kept for edge), and revalidateTag() calls specify a cacheLife profile.

Frequently asked questions

Can I go straight to Next.js 16 from 15?

Yes. 15 → 16 is a single, well-supported major step with no intermediate stop. The main prerequisite is finishing the async request-API migration, since the synchronous shim that warned in 15 is fully removed in 16.

Will the codemod do everything?

It does most of the mechanical work — the version bump, moving the turbopack config, migrating next lint to the ESLint CLI, renaming middleware to proxy, removing unstable_ prefixes, and dropping experimental_ppr. You still manually await any remaining sync request APIs and add cacheLife profiles to revalidateTag() calls.