# What's New in Next.js 16.4

> Next.js 16.4 makes Cache Components the default for new apps. Here's what changed, from ensureStatic to agent upgrades and Turbopack, in plain English.

- Author: Aayush Bharti
- Published: 2026-10-07
- Reading time: 11 min
- Tags: nextjs, react, caching, turbopack
- URL: https://aayushbharti.in/blog/nextjs-16-4-whats-new

**TL;DR:** Next.js 16.4 recommends Cache Components for every app and enables them by default in create-next-app. It adds ensureStatic to guarantee static routes, navigation() and prefetch() to control what loads during prefetching, an agent-driven upgrade command, and free Turbopack improvements like a 20–25% smaller dev cache.

---
Every few months Next.js ships a new release, and every time I open the release notes I understand about half of it on the first read. Version 16.4 landed on October 6, 2026, and this one has a lot packed in: new route configs, AI agents that upgrade your app, a pile of Turbopack internals, and a big change in status for a caching model that's been around for a year.

Most of it boils down to one decision and a handful of free wins. Cache Components isn't new (it shipped in Next.js 16), but until now it came with a "not for every app yet" asterisk. In 16.4 the Next.js team drops the asterisk, recommends Cache Components for every Next.js app, and switches it on for every new project made with `create-next-app`. The rest of the release either supports that model or makes your dev server lighter.

## Next.js 16.4 at a glance

If you only have a minute, this table covers it.

| Change | What it means | Do you need to act? |
| --- | --- | --- |
| Cache Components recommended | Caching is opt-in, per component, with `'use cache'` | New apps: already on. Existing apps: migrate when ready |
| `ensureStatic` | Build fails if a page you want static becomes dynamic | Optional, great for blogs and marketing sites |
| `navigation()` and `prefetch()` | Choose what loads during a prefetch vs a real click | Optional |
| `next upgrade --agent` | Your AI coding agent runs the upgrade for you | Optional |
| Turbopack improvements | Smaller cache, less dev work, smaller bundles | No, you get them by upgrading |
| React 19.3 | Stable View Transitions and Fragment Refs | No, it ships with 16.4 |

## What are Cache Components in Next.js?

Before Cache Components, the App Router cached things for you implicitly, and figuring out *why* a page was stale was a hobby in itself (ask anyone who debugged a `fetch` cache in Next.js 13). Cache Components flips that: nothing is cached unless you say so.

You mark a component or function with `'use cache'`, and set how long it stays fresh with `cacheLife()`. The Next.js team describes it as a component-level version of the `Cache-Control` header, which is the cleanest mental model I've seen for it.

```tsx title="app/dashboard/page.tsx"
import { cacheLife } from "next/cache";
import { Suspense } from "react";

export default async function DashboardPage() {
  const user = await getCurrentUser(); // runs on every request

  return (
    <div>
      <p>Welcome, {user.name}</p>
      <Suspense fallback={<p>Loading projects…</p>}>
        <Projects userId={user.id} />
      </Suspense>
    </div>
  );
}

async function Projects({ userId }: { userId: string }) {
  "use cache";
  cacheLife("hours"); // cached for hours, per userId

  const projects = await getProjects(userId);
  return projects.map((p) => <p key={p.id}>{p.name}</p>);
}
```

The welcome message is personal, so it renders on every request, while the project list comes from the cache. Both arrive in the same response.

### Cache Components isn't new in 16.4

You may have seen `'use cache'` before. Cache Components has been building up over several releases, and 16.4 is where it stops being optional advice:

| Version | What happened |
| --- | --- |
| Next.js 15 | `'use cache'` appears as an experimental feature behind the `experimental.dynamicIO` flag |
| Next.js 16 (October 2025) | Ships as Cache Components behind `cacheComponents: true`. `dynamicIO` and the old `ppr` flags are removed |
| Next.js 16.3 (2026) | Adds Partial Prefetching, which prefetches one reusable shell per route instead of every link |
| **Next.js 16.4 (October 2026)** | **Recommended for every app, on by default in `create-next-app`** |
| Next.js 17 | Becomes the default for all apps |

What 16.4 adds is a fix for the leftover gaps. There were cases where Cache Components couldn't match the cost and performance of the old model, and the features below (`ensureStatic`, `navigation()`, `prefetch()`) close them.

### How to turn it on

New apps from `create-next-app` already have it. For an existing app, add two flags:

```ts title="next.config.ts"
import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  cacheComponents: true,
  partialPrefetching: true,
};

export default nextConfig;
```

`partialPrefetching` arrived in [Next.js 16.3](https://nextjs.org/blog/next-16-3-instant-navigations) and is now considered part of the model, so turn on both. Cache Components becomes the default in Next.js 17, so you're migrating either way. I'd rather do it on my own schedule than during a major version bump.

## How to keep pages static with ensureStatic

Mixing static and dynamic content is powerful, but it has one sneaky downside. Someone adds a `<UserAvatar />` to your blog post layout, and suddenly every blog page renders on the server at request time. Your hosting bill notices before you do.

`ensureStatic` is a guardrail for that. Export it from a page or layout with the value `"navigation"`, and Next.js errors in `next dev` and fails `next build` if anything on that route needs request-time rendering:

```tsx title="app/about/page.tsx"
export const ensureStatic = "navigation";

export default function Page() {
  return (
    <>
      <UserAvatar /> {/* reads cookies, so the build fails */}
      <Content />
    </>
  );
}
```

Wrapping `<UserAvatar />` in `<Suspense>` doesn't get you out of it. With `"navigation"`, uncached `fetch` or database calls, `cookies()`, `headers()`, server-side `searchParams`, and short-lived caches (a `cacheLife` that expires in under five minutes) all fail the check. Data cached with `'use cache'` is fine.

There are three levels. Each stricter level includes the ones below it:

- `"navigation"`: the whole server-rendered route must be static. This is the only level that fails the build, and it works with Cache Components alone.
- `"prefetch"`: the shell and per-link prefetches (`<Link prefetch>`) must come from static output.
- `"shell"`: only the shell that every plain `<Link>` loads must be static.

`"prefetch"` and `"shell"` only do something when Partial Prefetching is on, and they don't add build validation. Despite the name, they tell Next.js to serve those stages from static output rather than guaranteeing it at build time.

A few rules to know before you add it:

1. It needs `cacheComponents: true`, or the build fails.
2. With `"navigation"`, a dynamic route like `app/blog/[slug]/page.tsx` needs a `generateStaticParams()` that returns at least one full set of params, or the build fails.
3. A child segment can be stricter than its parent but never looser. If `app/blog/layout.tsx` sets `"prefetch"`, a page under it can set `"navigation"`, but not `"shell"`.

That third rule shapes how you roll it out. Setting `"navigation"` on the root layout locks the entire site to static, and no nested page can opt out. If some pages need dynamic data later, move the export down from the root layout to the layouts that should stay static (like `app/blog/layout.tsx`) instead of trying to override it.

For blogs, docs, ecommerce product pages, and marketing sites, I'd add this today. A build error is a much cheaper way to find out than a surprise bill.

## How to stop prefetching from loading too much

Prefetching makes navigation feel instant. `<Link prefetch>` loads a page's cached UI before the user clicks, so there's no spinner. The catch: it loads *everything* cached on that page, for every visible link, including pages the user never opens.

Picture an email inbox with 50 visible messages. With `prefetch` on, you load 50 full email threads up front. That's a lot of database work for emails nobody reads.

Next.js 16.4 adds `navigation()`. Await it inside a component, and that component is skipped during prefetching and only loads on a real click:

```tsx title="app/message/[id]/page.tsx"
import { navigation } from "next/cache";
import { Suspense } from "react";

async function Message({ id }: { id: string }) {
  const message = await getMessage(id); // included in the prefetch

  return (
    <>
      <h1>{message.subject}</h1>
      <div>{message.body}</div>
      <Suspense fallback={<p>Loading thread…</p>}>
        <Thread id={id} />
      </Suspense>
    </>
  );
}

async function Thread({ id }: { id: string }) {
  await navigation(); // skipped during prefetch, loads on click
  const thread = await getThread(id);
  return thread.map((m) => <div key={m.id}>{m.body}</div>);
}
```

Now the prefetch loads the first message (instant open), and the rest of the thread waits until someone clicks.

There's also a sibling, `prefetch()`, imported from the same place. Await it to keep content out of the route's shell (the part every plain `<Link>` loads), so it only renders on an explicit `<Link prefetch>` or a real navigation. Rule of thumb: `navigation()` means "wait for the click," `prefetch()` means "wait for an explicit prefetch."

Both throw without `cacheComponents`, and both are built for Partial Prefetching. Without `partialPrefetching`, `prefetch()` does nothing and `<Link prefetch>` fetches the whole route anyway, deferred thread included, which undoes the inbox fix. They also throw inside a `'use cache'` function. Await them in the component, then call your cached functions below that line, like `Thread` does above.

## How to upgrade to Next.js 16.4

You have two options. The classic one:

```bash title="Terminal"
npm install next@latest
```

Or let your AI coding agent do it:

```bash title="Terminal"
npx next@canary upgrade --agent=latest
```

The `--agent` mode checks your installed version, picks the target release, and hands your agent the migration guides, codemods, and verification steps. The agent applies the upgrade, fixes what breaks, and checks the app still works. Using `next@canary` here means you get the newest upgrade tooling even if your app is several versions behind.

Two related experimental flags are worth knowing about:

- `experimental.agentUpgrade`: `next dev` and `next build` remind you when an upgrade is available. The default, `"security"`, only nags about known vulnerabilities in your version. `"latest"` reminds you about every minor and major release. `false` turns it off.
- `experimental.agentFeedback`: when your agent hits a framework bug or unclear docs, it drafts a report for the Next.js team. You review each draft in the browser, and nothing is sent until you click **Send feedback**. It's on by default for new apps created with the recommended `create-next-app` settings, needs Next.js telemetry enabled, and doesn't run in CI.

If you're migrating an existing app to Cache Components, the Next.js team also publishes [agent Skills for Cache Components adoption](https://nextjs.org/docs/app/guides/ai-agents) that walk your agent through the refactor.

## Free improvements you get by upgrading

None of these need config changes:

- The Turbopack disk cache is 20–25% smaller. It now uses Zstandard compression for the bulky data and cleans out stale entries more aggressively.
- Server HMR is lazy. Edit a shared server file, and only the page you're looking at recompiles; pages you visited earlier wait until you open them again.
- Turbopack ships its runtime as one chunk shared across routes, so browsers download it once and cache it better.
- Production bundles are smaller, thanks to shorter CSS Module class names and export mangling that shortens internal JavaScript export names.
- React 19.3 comes along, with stable View Transitions, Fragment Refs, and a new `browser()` API. The [React 19.3 announcement](https://react.dev/blog/2026/09/09/react-19-3) has the details.

If you're chasing Lighthouse scores, the bundle changes stack nicely with the techniques in my [Next.js optimization guide](/blog/how-to-optimize-a-nextjs-web-app).

## Experimental Turbopack flags worth trying

These sit behind flags, so treat them as "try in a branch first." All of them go under `experimental` in `next.config.ts`.

| Flag | What it does |
| --- | --- |
| `turbopackRustReactCompiler: true` | Runs the React Compiler in Rust instead of Babel. 30% less memory and 15% faster compiles in this release. Needs `reactCompiler: true` |
| `turbopackGc: true` | Garbage-collects unused compile work from memory and disk, including leftovers from deleted routes |
| `turbopackLazyDynamicImports: true` | Compiles client-side `import()` code only when the browser asks for it |
| `turbopackPluginRuntimeStrategy: "workerThreads"` | Runs Babel, PostCSS, and webpack loaders in worker threads instead of separate processes |
| `turbopackAdditionalRoots` | Follows symlinked packages outside your project root, including pnpm and Bun global stores |

One gotcha: on Node.js 24.13.1 and newer, the worker threads option falls back to child processes because of a [Node.js bug](https://github.com/nodejs/node/issues/65100). So if you turn it on and see no difference, that's probably why.

The Turbopack Bundle Analyzer also got a big update: a route summary page that shows your largest client routes, a sortable table view, automatic snapshots you can diff over time, and markers for modules on the critical render path (with an option to filter out async dependencies). There's an agent skill for it too:

```bash title="Terminal"
npx skills add vercel/next.js --skill next-bundle-optimizer
```

Then run `/next-bundle-optimizer` in your agent.

## Should you upgrade to Next.js 16.4?

Yes. The upgrade itself is low-risk: the Turbopack and bundle improvements need no changes, and anything that changes behavior sits behind a flag. Bump the version and run your build.

The bigger question is Cache Components, and my answer depends on where you are. Starting something new? It's on by default, so keep it. Running an existing app? Start the migration now while it's optional, one route at a time, and add `ensureStatic` to the pages you know should never be dynamic. When Next.js 17 makes it the default, you'll already be done instead of migrating under pressure.

If you want help untangling caching in a real codebase, or you've got a Next.js app that's slower than it should be, [get in touch](/contact).

## Frequently asked questions

### What is new in Next.js 16.4?

Next.js 16.4 recommends Cache Components for every app and turns them on by default for new projects. It adds the ensureStatic route config, the navigation() and prefetch() functions for controlling prefetching, next upgrade --agent for AI-assisted upgrades, React 19.3, a 20–25% smaller Turbopack disk cache, lazy server HMR, and smaller production bundles.

### What are Cache Components in Next.js?

Cache Components is the Next.js programming model where caching is opt-in. You mark a component or function with the 'use cache' directive and set how long it stays fresh with cacheLife(). Everything else renders at request time. Cached and dynamic parts can stream together in a single response.

### Are Cache Components new in Next.js 16.4?

No. 'use cache' first appeared as an experimental feature in Next.js 15, and Cache Components shipped behind the cacheComponents flag in Next.js 16 in October 2025. Next.js 16.3 added Partial Prefetching. What's new in 16.4 is the status: the Next.js team now recommends Cache Components for every app, and create-next-app enables it by default.

### How do I enable Cache Components in Next.js 16.4?

Set cacheComponents: true and partialPrefetching: true in next.config.ts. New apps created with create-next-app in 16.4 have this enabled already. Cache Components will become the default in Next.js 17.

### What does ensureStatic do in Next.js?

ensureStatic is a route segment config, new in Next.js 16.4, that requires parts of a route to be static. With 'navigation', the build fails if anything on the route needs request-time rendering. 'prefetch' and 'shell' serve per-link prefetches or the App Shell from static output when Partial Prefetching is on. It requires cacheComponents, applies to every page under a layout, and child segments can only be stricter, never looser.

### How do I upgrade to Next.js 16.4?

Run npm install next@latest to upgrade manually, or run npx next@canary upgrade --agent=latest to have your coding agent handle the upgrade, including migration guides, codemods, and verification steps.

### Is Next.js 16.4 a breaking upgrade?

No. Cache Components is still opt-in for existing apps through the cacheComponents flag. The Turbopack improvements and React 19.3 apply without config changes, and the new Turbopack features like garbage collection and lazy dynamic imports sit behind experimental flags.
