Migrating to Next.js 16: A Field Guide
We've now migrated a dozen production codebases to Next.js 16. The headline features get the blog posts, but here's what actually consumes your migration day.
Turbopack is the default — and it's stricter
Turbopack statically analyzes imports. Code that "worked" under webpack because a bad import was never executed now fails the build. This is a feature: we found three latent bugs in one client codebase this way.
next lint is gone
Move to the ESLint CLI directly. eslint-config-next now ships native flat configs, so delete your FlatCompat shim:
import nextVitals from "eslint-config-next/core-web-vitals";
import nextTs from "eslint-config-next/typescript";
export default [...nextVitals, ...nextTs];
Check your peer versions
Not every tool in the ecosystem keeps pace. As of this writing, stick with ESLint 9 and TypeScript 6 — the config presets and build tooling aren't ready for ESLint 10 or TS 7.
Async params are non-negotiable
If you skipped the Next 15 codemod, params and searchParams as plain objects will now break. The codemod handles 95% of cases: npx @next/codemod@latest next-async-request-api .
The payoff
Across our migrations: 40–70% faster production builds, faster dev server startup, and hot reloads that feel instant. Budget a day for a mid-size app, and do it before the version gap grows.