By Chirag Chudasama··5 min read
Next.js 16.3 upgrade notes: what changed and what to do first
Explicit caching, proxy.ts, a stable React Compiler and faster Turbopack builds: the Next.js 16 changes that matter, and the order I upgrade in.
- Next.js
- Performance
Key takeaways
- Next.js 16 needs Node.js 20.9+, makes request APIs async, renames middleware.ts to proxy.ts and changes revalidateTag.
- Cache Components make caching opt-in with 'use cache'; turn them on in a separate change after the upgrade.
- Turbopack is the default bundler, and 16.3 adds a build cache that only speeds up CI if you restore .next/cache between runs.
Next.js 16 changed more than a typical major release. Caching went from implicit to opt-in, middleware got a new name, and Turbopack became the default bundler. The 16.3 release in mid-2026 then made builds much faster. This site runs on Next.js 16.3, and these are the notes I use when upgrading client projects.
Before you start
Check the platform requirements. Next.js 16 needs Node.js 20.9 or newer and TypeScript 5.1 or newer, and supports Chrome, Edge and Firefox 111+ and Safari 16.4+. Most upgrades fail on the Node version on the server, not on the code, so check your host first.
Then run the official codemod, which handles most of the mechanical changes:
npx @next/codemod@canary upgrade latestThe breaking changes that bite
Request APIs are async everywhere
Synchronous access to params, searchParams, cookies(), headers() and draftMode() has been removed. You now await them. The codemod fixes most cases, but check any helper that received params as an argument.
type Props = { params: Promise<{ slug: string }> }
export default async function Page({ params }: Props) {
const { slug } = await params
// ...
}middleware.ts is now proxy.ts
Rename the file to proxy.ts and the exported function to proxy. The logic stays the same, and it now runs on the Node.js runtime. The old middleware.ts still works for Edge use cases, but it is deprecated.
revalidateTag needs a second argument
revalidateTag() now takes a cacheLife profile, which gives stale-while-revalidate behaviour. The one-argument form is deprecated. If a user should see their own change straight away, such as after saving a form, use the new updateTag() inside a Server Action instead.
import { revalidateTag, updateTag } from "next/cache"
// Content that can be briefly stale: serve cached, refresh in background
revalidateTag("blog-posts", "max")
// In a Server Action, when the user must see their own write
updateTag(`user-${userId}`)Smaller changes worth a search
- next lint is gone, and next build no longer lints. Run ESLint or Biome directly in CI.
- next/image defaults changed. The minimum cache TTL went from 60 seconds to 4 hours, the default quality list is now just 75, and local images with query strings need images.localPatterns.
- Every parallel route slot now needs an explicit default.js, or the build fails.
- AMP support, serverRuntimeConfig and publicRuntimeConfig are removed. Use environment variables.
Cache Components: caching you can see
The biggest conceptual change is Cache Components. Earlier App Router versions cached things implicitly, which confused almost everyone at some point. With Cache Components turned on, dynamic code runs at request time by default, and you opt into caching with the 'use cache' directive on a page, component or function. The compiler generates the cache keys.
// next.config.ts
const nextConfig = {
cacheComponents: true,
}
export default nextConfigIt also completes Partial Prerendering. A page can serve a static shell instantly and stream in the dynamic parts through Suspense. My advice is to upgrade first with it off, then turn it on as a separate change and add 'use cache' where you actually want caching. Two changes in two pull requests are far easier to debug than one big one.
Performance you get almost for free
Turbopack has been the default bundler since 16.0. The Next.js team reported 2–5x faster production builds and up to 10x faster Fast Refresh. If you have a custom webpack setup, next build --webpack keeps it working while you migrate.
16.3 added two things I'd point out:
- The Turbopack file-system cache now covers next build and is on by default. The Next.js team measured nextjs.org's compile step going from 21 seconds cold to 9.2 seconds cached. The cache lives in .next/cache, so builds in CI only get faster if you restore that folder between runs. Most pipelines need a one-line change for this.
- Dev-server memory eviction is on by default. On Vercel's own dashboard app, memory after compiling 50 routes dropped from 21.5 GB to 2 GB. That matters now that coding agents, type-checkers and editors all compete for the same RAM.
The React Compiler
React Compiler support has been stable since Next.js 16.0. It memoises components automatically, so most hand-written useMemo and useCallback calls become unnecessary. It is still opt-in with reactCompiler: true, because the Babel version slows builds down. 16.3 adds an experimental Rust version of the compiler, which the Next.js team measured as 20–50% faster to compile on large apps like v0.
const nextConfig = {
reactCompiler: true,
experimental: {
turbopackRustReactCompiler: true,
},
}I enable it on new projects. On existing ones, I turn it on after the upgrade has settled and check the pages with the heaviest interaction first.
React 19.2 extras
The App Router ships with React 19.2 features. The one I use most is View Transitions: on this site, clicking a project in the portfolio morphs its preview into the case-study hero using React's ViewTransition component, without an animation library. useEffectEvent and the Activity component are also worth knowing.
The order I upgrade in
- Update Node.js on the server and in CI.
- Run the codemod and fix what it couldn't: async params, proxy.ts, revalidateTag calls.
- Replace next lint with a direct ESLint step, and restore .next/cache in CI.
- Test images, redirects and anything that used middleware.
- Ship that on its own.
- Then, separately: enable Cache Components, then the React Compiler, one pull request each.
Upgrading this way is boring, and that's the goal. Every step is easy to review and easy to roll back, and the site keeps working throughout.
Sources
Written by
Chirag Chudasama · Full stack web developer
I'm a full stack web developer who has spent the last few years helping founders, agencies and local businesses turn ideas into products people enjoy using. Find me on GitHub and LinkedIn.