HTML / CSS

Next.js 15 to 16: Turbopack by Default, Async APIs, and Opt-In Caching

Next.js 15 RC shipped with a few changes that actually matter for how I build apps. Here's what stood out.

26 May 2024

Next.js 15 to 16: Turbopack by Default, Async APIs, and Opt-In Caching

When I first wrote about Next.js 15 it was a release candidate. It has long since shipped, and Next.js 16 followed it. The two releases together mark the biggest shift in how Next.js behaves since the App Router: the bundler changed, request APIs became async, and caching flipped from opt-out to opt-in. If you are still on 14 or dragging a 15 upgrade, here is what actually changed and why it matters.

Turbopack is the default now

For years next dev and next build ran on webpack. Turbopack, the Rust-based bundler, was experimental, then stable for dev in 15, and in 16 it is the default for both dev and build. Vercel reports roughly 87% faster cold dev startup, 75% faster Fast Refresh, and 2.5x faster production builds against webpack. Next.js 16 also adds Turbopack filesystem caching, storing compiler artifacts on disk so restarts are fast too.

For most projects the upgrade is transparent. If you had a custom webpack config in next.config.js, that is the part that needs attention.

Async request APIs

This is the breaking change that catches everyone. cookies(), headers(), draftMode(), and the params and searchParams props are now asynchronous. Next.js 15 introduced this with temporary synchronous compatibility; Next.js 16 removed the synchronous access entirely.

Typescript
// Before
export default function Page({ params }: { params: { id: string } }) {
  const id = params.id;
}

// Next.js 15/16
export default async function Page({ params }: { params: Promise<{ id: string }> }) {
  const { id } = await params;
}
Typescript
import { cookies } from "next/headers";

export async function getSession() {
  const cookieStore = await cookies(); // now awaited
  return cookieStore.get("session")?.value;
}

The reasoning is real: making these async lets Next.js start rendering before the request is fully resolved. A codemod handles most of the mechanical rewrite, but you should understand why it is happening.

Caching is opt-in now

The old App Router cached aggressively and surprised people constantly. fetch() was cached by default, and so were GET route handlers. That is reversed:

  • fetch() is no longer cached by default. You opt in explicitly.
  • GET route handlers are no longer cached by default.
  • The client router cache no longer reuses page data by default.
Typescript
// Opt in to caching explicitly now
const res = await fetch("https://api.example.com/data", {
  cache: "force-cache",
  next: { revalidate: 3600 },
});

Next.js 16 pushes further with an explicit use cache directive and cache components, moving caching from implicit framework magic to something you declare. revalidateTag now also takes a cache-life profile argument; the single-argument form is deprecated.

The React Compiler config is stable

The reactCompiler option graduated from experimental to a stable config flag. It is not on by default yet, Vercel is still gathering build-performance data across app types, but you can enable it deliberately. Remember it is the React Compiler doing the work, a separate tool from React itself.

Should you upgrade?

Yes, but stage it:

  1. Move to 15 first if you are on 14, run the async-request codemod, and audit every fetch you relied on being cached, that is where behavior silently changes.
  2. Then take 16 for the Turbopack build default and the explicit caching model.
  3. Enable reactCompiler as its own separate experiment once you are stable.

The theme across both releases is honesty: the framework stopped caching and resolving requests behind your back, and made you say what you want. More explicit, less magic, fewer 2am "why is this stale" incidents.

Wrapping up

Next.js 15 and 16 are not a feature drop, they are a change in defaults: Turbopack instead of webpack, async request APIs instead of sync, and opt-in caching instead of opt-out. The upgrade takes real work if you leaned on the old implicit behavior, but the result is a framework whose performance characteristics you can actually reason about.

Go further
Live cohort on Maven

From Senior to Staff: Master the Architecture Skills That Get You Promoted

Go from shaky in design reviews to the engineer everyone trusts to architect the hard stuff.

View the live cohort

Keep reading