Next.js 16 finishes many of the changes that Next.js 15 started. Turbopack is now the default bundler, the temporary synchronous request APIs are gone, middleware becomes proxy, and caching gets a cleaner set of APIs. This guide walks through what changed and how to upgrade an existing App Router project.
Requirements
- Node.js 20.9 or later. Node.js 18 is no longer supported.
- TypeScript 5.1 or later, if you use TypeScript.
- Browsers: Chrome and Edge 111+, Firefox 111+, Safari 16.4+.
Step 1: run the upgrade codemod
npx @next/codemod@canary upgrade latest
It updates next, react and react-dom, moves Turbopack config to its new location, migrates next lint to the ESLint CLI, renames middleware to proxy, and removes the unstable_ prefix from APIs that are now stable.
If your code still reads params, searchParams, cookies() or headers() synchronously, also run:
npx @next/codemod@canary next-async-request-api .
Turbopack is the default
next dev and next build now use Turbopack without the --turbopack flag, so you can drop it from your package.json scripts. If you have a custom webpack config that you cannot migrate yet, opt out with next build --webpack.
Turbopack options move from experimental.turbo to a top-level turbopack key:
// next.config.js
const nextConfig = {
turbopack: {
resolveAlias: { underscore: 'lodash' },
},
};
export default nextConfig;
Request APIs are async only
Next.js 15 made params, searchParams, cookies(), headers() and draftMode() async but still allowed synchronous access with a warning. In Next.js 16 that compatibility layer is removed, so you must await them:
export default async function PostPage({ params }) {
const { slug } = await params;
const post = await getPost(slug);
return <h1>{post.title}</h1>;
}
The same applies to the params passed to opengraph-image, icon and sitemap functions.
middleware.js is now proxy.js
mv middleware.js proxy.js
// proxy.js
import { NextResponse } from 'next/server';
export function proxy(request) {
if (!request.cookies.has('session')) {
return NextResponse.redirect(new URL('/login', request.url));
}
}
export const config = { matcher: ['/dashboard/:path*'] };
proxy always runs on the Node.js runtime. If you depend on the Edge runtime, keep using middleware for now; it is deprecated, not removed. Config flags were renamed too, for example skipMiddlewareUrlNormalize is now skipProxyUrlNormalize.
New caching APIs
revalidateTag needs a cache profile
// Before
revalidateTag('posts');
// After: serve stale content while it refreshes in the background
revalidateTag('posts', 'max');
updateTag for read-your-writes
updateTag can only be called in Server Actions. It expires the cache and refreshes it in the same request, so a user who saves a form sees their change straight away:
'use server';
import { updateTag } from 'next/cache';
export async function saveProfile(userId, data) {
await db.users.update(userId, data);
updateTag(`user-${userId}`);
}
A third helper, refresh(), refreshes the client router from inside a Server Action.
Cache Components replace the PPR flag
The experimental ppr flag and the experimental_ppr segment config are gone. Partial Prerendering is now enabled through Cache Components, together with the 'use cache' directive:
// next.config.js
const nextConfig = { cacheComponents: true };
export default nextConfig;
next/image defaults changed
images.minimumCacheTTLnow defaults to 4 hours instead of 60 seconds.images.qualitiesdefaults to[75], so otherqualityvalues are snapped to 75 unless you list them.- Local images with query strings need a matching
images.localPatternsentry. - Optimizing images from local IPs is blocked by default, and
images.domainsis deprecated in favour ofremotePatterns.
Other changes to check
- React 19.2 ships with the App Router, and React Compiler support is stable through the
reactCompileroption. - Every parallel route slot now needs a
default.jsfile, or the build fails. next lintis removed. Run ESLint directly with a flat config.- AMP support and
serverRuntimeConfig/publicRuntimeConfigare removed. Use environment variables instead. next devandnext builduse separate output folders, so you can run both at the same time.
Upgrade checklist
- Upgrade Node.js to 20.9 or later.
- Run the
upgradecodemod, then the async request API codemod if needed. - Remove
--turbopackfrom scripts and move Turbopack config to the top level. - Rename
middleware.jstoproxy.js. - Add a cache profile to every
revalidateTagcall. - Review your
next/imageconfig. - Run
next buildand fix whatever it reports.
For most App Router projects the codemods do the heavy lifting, and the upgrade takes under an hour. This site runs on Next.js 16 too.


Comments