← Blog

Next.js 16 vs Next.js 15: What Changed and Should You Upgrade?

·4 min read·Next.jsReactWeb Development

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

FeatureNext.js 15Next.js 16
React versionReact 19React 19 (stable)
TurbopackOpt-in (beta)Default in dev
fetch cachingNo-store by defaultNo-store by default
<Form> component✅ Improved
Async params / searchParamsRequiredRequired
next/afterExperimentalStable
PPR (Partial Prerendering)ExperimentalIncremental stable
Node.js minimum18.1818.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 dev

In 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):

MetricNext.js 15Next.js 16
next dev cold start~8s~3.5s
HMR (hot reload)~300ms~80ms
next build~45s~42s
Lighthouse score (PPR route)8896

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 params migration

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 upgrade

Then 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.