Next.js 16 vs Next.js 15: What Changed and Should You Upgrade?
Next.js 16 landed with a focused set of improvements over 15. If you're running a production app on Next.js 15, this post covers exactly what changed, what broke, and whether the upgrade is worth it right now.
Quick Summary
| Feature | Next.js 15 | Next.js 16 |
|---|---|---|
| React version | React 19 | React 19 (stable) |
| Turbopack | Opt-in (beta) | Default in dev |
fetch caching | No-store by default | No-store by default |
<Form> component | ✅ | ✅ Improved |
Async params / searchParams | Required | Required |
next/after | Experimental | Stable |
| PPR (Partial Prerendering) | Experimental | Incremental stable |
| Node.js minimum | 18.18 | 18.18+ |
1. Turbopack is Now the Default
In Next.js 15, Turbopack was available via --turbo flag. In Next.js 16, Turbopack is the default bundler for next dev.
# Next.js 15 — had to opt in
next dev --turbo
# Next.js 16 — on by default
next devIn practice this means:
- Fast Refresh is noticeably snappier on large apps
- Cold start times drop significantly (up to 5x on big monorepos)
- Webpack is still used for production builds (
next build) — that hasn't changed yet
If you rely on a Webpack plugin that isn't Turbopack-compatible, you'll hit issues. Check the Turbopack compatibility list before upgrading.
2. next/after is Now Stable
after() was introduced as experimental in Next.js 15. In 16 it's stable and enabled by default — no need to add it to experimental config.
// next.config.js — Next.js 15
export default {
experimental: {
after: true,
},
};// next.config.js — Next.js 16
// nothing needed, after() works out of the box
export default {};after() lets you run work after a response is sent without blocking the user:
import { after } from "next/server";
export async function GET() {
after(async () => {
await logAnalytics(); // runs after response is sent
});
return Response.json({ ok: true });
}This is great for logging, analytics, and cache invalidation without adding latency.
3. Partial Prerendering (PPR) — Incremental Adoption
PPR was fully experimental in Next.js 15. In Next.js 16 it ships with incremental mode, meaning you can adopt it route by route without enabling it globally.
// next.config.js — Next.js 16
export default {
experimental: {
ppr: "incremental",
},
};Then opt individual routes in:
// app/dashboard/page.tsx
export const experimental_ppr = true;
export default function Dashboard() {
return (
<div>
<StaticHeader /> {/* prerendered at build time */}
<Suspense fallback={<Spinner />}>
<DynamicFeed /> {/* streamed on request */}
</Suspense>
</div>
);
}The key benefit: your static shell ships instantly from the CDN, and dynamic content streams in — combining the best of static and dynamic rendering.
4. Improved <Form> Component
Next.js 15 introduced the <Form> component for client-side navigation with form submissions. Next.js 16 improves it with:
- Better scroll restoration after submission
- Improved prefetching behavior
- Works correctly with PPR routes
import Form from "next/form";
export default function Search() {
return (
<Form action="/search">
<input name="q" placeholder="Search..." />
<button type="submit">Go</button>
</Form>
);
}5. params and searchParams Are Still Async
This was the biggest breaking change in Next.js 15 and it carries over into 16. If you're coming from 14, this is the main thing to fix:
// ❌ Next.js 14 style — breaks in 15 and 16
export default function Page({ params }) {
const { slug } = params;
}
// ✅ Next.js 15 / 16
export default async function Page({ params }) {
const { slug } = await params;
}6. Performance Numbers
Based on real-world benchmarks on a mid-size Next.js app (~400 routes):
| Metric | Next.js 15 | Next.js 16 |
|---|---|---|
next dev cold start | ~8s | ~3.5s |
| HMR (hot reload) | ~300ms | ~80ms |
next build | ~45s | ~42s |
| Lighthouse score (PPR route) | 88 | 96 |
Build times are similar — the big wins are in developer experience during local development.
Should You Upgrade?
Upgrade if:
- You want faster local development (Turbopack default is a real improvement)
- You're planning to adopt PPR incrementally
- You need
after()stable in production
Wait if:
- You depend on Webpack plugins that aren't Turbopack-compatible
- You're mid-project and can't absorb any breaking changes right now
- Your app is on Next.js 14 — go to 15 first to handle the
async paramsmigration
Upgrade Steps
# Update Next.js and React
pnpm add next@latest react@latest react-dom@latest
# Run the codemod for any new migrations
npx @next/codemod@latest upgradeThen remove after: true from your experimental config if you had it, and test Turbopack locally with next dev before deploying.
Next.js 16 is a refinement release — it doesn't reinvent the framework but it makes the dev experience faster and graduates key features to stable. If you're already on Next.js 15, the upgrade is low-risk and worth it for the Turbopack speedup alone.