← Blog

Next.js 16 upgrade checklist: every breaking change, the error you'll see, and the fix

By VibeBoot ·

Short on time? The SaaS Starter already has this wired up: $49 one-time, 14-day money-back guarantee.

Upgrading a Next.js 15 app to Next.js 16 is mostly renames and removals, but a few of them fail silently, and coding agents trained on older code keep writing the old version back in. This checklist covers every breaking change in the official upgrade guide, what you'll see when it bites, and the fix. Work through it top to bottom.

Everything below was checked on Nov 2, 2026 against the official Next.js 16 upgrade guide. Both VibeBoot starters already run on Next.js 16.4 with proxy.ts and async params.

The 60-second version

ChangeWhat you'll seeFix
Sync params, searchParams, cookies(), headers() removedparams.slug is undefined, or a type errorconst { slug } = await params
middleware.ts renamed to proxy.ts"The middleware file convention is deprecated" warningRename the file and the function to proxy
Turbopack is the default for next buildBuild fails because a webpack config was foundMigrate it, or build with --webpack
next lint removednext lint script stops workingRun eslint directly
revalidateTag(tag) needs a second argumentTypeScript error on revalidateTagrevalidateTag(tag, "max") or updateTag(tag)
Parallel route slots need default.jsBuild fails on an @slot folderAdd default.tsx that returns null
next/image defaults tightenedImages 400, or come out at a different qualitySet images.qualities, localPatterns, remotePatterns
serverRuntimeConfig and publicRuntimeConfig removedgetConfig() returns nothing usefulUse env vars
Node.js 18 droppedInstall or build fails on old CI imagesNode.js 20.9 or newer

Step 0: run the codemods first

npx @next/codemod@canary upgrade latest

That one command updates next.config for top-level turbopack, moves next lint to the ESLint CLI, renames middleware to proxy, drops the unstable_ prefix from stabilized APIs and removes experimental_ppr.

It does not migrate synchronous request APIs. If your app still reads params or cookies() without await, also run:

npx @next/codemod@canary next-async-request-api .

Then search the diff for UnsafeUnwrapped and codemod error comments. Those are the spots it couldn't fix for you.

If you use Cursor or Claude Code, run npx @next/codemod@canary agents-md too. It points AGENTS.md at the docs bundled with your installed Next.js version, so the agent stops suggesting Next.js 14 patterns. More on that in Next.js 16 writes your AGENTS.md now.

1. Requirements: Node.js 20.9+, TypeScript 5.1+

Node.js 18 is no longer supported. Check your CI image, your Dockerfile and the Node version your host uses. Browser support is now Chrome/Edge/Firefox 111+ and Safari 16.4+. Upgrade @types/react and @types/react-dom along with next, react and react-dom.

2. Async request APIs: the silent one

Next.js 15 made params, searchParams, cookies(), headers() and draftMode() async, but kept a synchronous fallback. Next.js 16 removes the fallback.

The dangerous part is that params.slug on a Promise is just undefined. If your types still say { params: { slug: string } }, TypeScript stays quiet and the page renders "not found".

// Next.js 16
export default async function Page(props: PageProps<"/blog/[slug]">) {
  const { slug } = await props.params;
  const query = await props.searchParams;
  return <h1>{slug}</h1>;
}

Run npx next typegen to get the global PageProps, LayoutProps and RouteContext helpers. The same change applies in layout, route handlers, default, and the opengraph-image, twitter-image, icon and apple-icon files. In image files, id from generateImageMetadata is now a Promise too, and so is id in a sitemap that uses generateSitemaps.

Full fix with the agent prompt: params.slug is undefined (params is a Promise).

3. middleware.ts becomes proxy.ts

Rename the file and the exported function:

mv middleware.ts proxy.ts
export function proxy(request: Request) {}

Two things to watch:

With Auth.js v5 the whole file can be export { auth as proxy } from "@/auth". Walkthrough: Auth.js v5 on Next.js 16. Paste your old file into the free middleware.ts → proxy.ts converter to see the diff, or read the deprecation warning fix.

4. Turbopack is now the default

next dev and next build use Turbopack, so you can drop --turbopack from your scripts. If anything adds a webpack config (often a plugin you didn't write), next build fails on purpose. Your options:

Two Turbopack differences that break builds: Sass imports with the ~ prefix (@import '~bootstrap/...') need the tilde removed, and client code that imports Node modules fails with Module not found: Can't resolve 'fs'. The right fix for that is to keep Node APIs in server code: Can't resolve 'fs' fix.

5. next lint is gone

next lint is removed, the eslint option in next.config is removed, and next build no longer lints. Replace the script with plain eslint (or Biome) and run it in CI yourself:

npx @next/codemod@canary next-lint-to-eslint-cli .

@next/eslint-plugin-next now defaults to flat config, so move off .eslintrc if you haven't.

6. Caching APIs changed signature

7. Parallel routes need default.js

Every @slot folder now needs an explicit default.js, or the build fails. To keep the old behavior:

export default function Default() {
  return null;
}

8. next/image defaults

None of these throw at build time. You find them when images look wrong or 400 in production.

9. Removed config and APIs

10. Small behavior changes worth knowing

Done? Check these before you ship

  1. npm run build passes on the Node version your host actually uses.
  2. Every dynamic route renders with real data. Click into a [slug] page, because the async params bug doesn't fail the build.
  3. Auth still protects what it should after the proxy.ts rename. Open a protected page in a private window.
  4. Images load in production at the quality you expect.
  5. CI runs eslint itself, since next build no longer does.
  6. Your AGENTS.md or Cursor rules say Next.js 16, so the agent doesn't undo all of this next week.

Still stuck on an error? Paste it into VibeBoot Doctor, which is free and runs in your browser, or browse the 70 fix pages for Next.js, Auth.js, Prisma and Stripe errors.