Next.js 16.4

Over the 16.x releases, we’ve introduced a new programming model that addresses many of the frustrations you've had with App Router from the start:

  • It brings fast initial loads, even for personalized pages

  • It gives server-rendered apps instant client navigations

  • It makes caching opt-in, declarative, and composable

This new programming model is called Cache Components, and it will become the default in Next.js 17.

Prior to this release, we didn’t recommend it universally because there were some cases where it couldn’t achieve the same cost and performance guarantees as with the previous model.

This release includes key features that close those gaps.

Starting with Next.js 16.4, we’re excited to recommend Cache Components as the best choice for every Next.js app.

As of today, all new apps created with create-next-app will have Cache Components enabled by default. Greenfield projects can enjoy all the benefits of the new model with no reservations.

For existing apps, we’ve been investing in better agentic tooling to help codebases migrate to the new model. The new next upgrade --agent command gives agents version-specific guidance on upgrading your app, and dedicated Skills help agents with any refactorings needed for you to adopt Cache Components.

Next.js 16.4 also includes several out-of-the-box improvements for all Next.js apps, including less memory usage and disk size in dev, reduced compile times, smaller production bundles, and React 19.3.

Here’s a full overview of what to expect in this release, starting with Cache Components.

What are Cache Components?

Cache Components are a suite of features that lets you mark specific parts of your component tree as eligible for caching. Think of 'use cache' as a component-level version of the Cache-Control HTTP header:

import { cacheLife } from 'next/cache';

export default async function DashboardPage() {
const currentUser = await getCurrentUser();

return (
<div>
<p>Welcome, {currentUser.name}</p>

<Suspense fallback={<Loading />}>
<Projects userId={currentUser.id} />
</Suspense>
</div>
);
}

async function Projects({ userId }) {
'use cache';
cacheLife('hours');

const projects = await db.query.projects.findMany({
where: eq(projectsTable.userId, userId),
});

return (
<div>
{projects.map((project) => (
<p key={project.id}>{project.name}</p>
))}
</div>
);
}

Next.js interprets these 'use cache' annotations as it renders your pages, caching your component's UI in the browser (during client navigations) and, optionally, on the server (during server rendering, or ahead of time during the build).

These composable annotations let you mix client-side caching, fully pluggable server-side caching, and request-time rendering all within a single page, and they replace the implicit caching behaviors of the previous App Router versions.

To learn more about Cache Components, read the guide on caching.

What's new in Cache Components

In this post, we use "Cache Components" to refer to the new programming model, which you can use today by enabling two flags in your Next.js config:

next.config.ts

import type { NextConfig } from 'next';

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

export default nextConfig;

Cache Components first shipped without Partial Prefetching, but it's now considered part of the model. You can learn more about Partial Prefetching from our previous release post.

Next, here's what's new for Cache Components in 16.4.

Ensuring shells, prefetches, or pages are static

One of the hallmark features of 'use cache' is the ability to build pages that stream static and dynamic content together in a single response from the server.

For example, you can compose the current user’s avatar alongside a blog post that is otherwise statically prerendered:

export default function Page() {
return (
<>
<UserAvatar />
<Content />
</>
);
}

// This component renders at request time
async function UserAvatar() {
const currentUser = await getCurrentUser();

// ...
}

// This component is statically prerendered
async function Content() {
'use cache';

await fetch('...');

// ...
}

Next.js can serve the prerendered blog post from cache (like your app's /public folder, or a CDN) and render the UserAvatar at request time, all from the same HTTP response.

This flexibility is what enables you to build apps with sophisticated UIs, without sacrificing speed or dynamism. But sometimes you want to build an app with fully static pages. In those cases, one dynamic component can degrade the performance or cost characteristics of an otherwise optimized site.

In Next.js 16.4, ensureStatic offers a simple way to guarantee that a route’s shell, prefetch, or full navigation is static. For apps that want to avoid unintentional compute and keep their server costs down, this lets you prevent a dynamic component from accidentally sneaking into a route.

For example, if we wanted to enforce that our blog post page from the example above was always static, and that adding a dynamic component like UserAvatar should never be possible, we could add export const ensureStatic to the route:

export const ensureStatic = 'navigation';

export default function Page() {
return (
<>
<UserAvatar /> {/* 🔴 This component fails the build */}
<Content />
</>
);
}

By setting ensureStatic to "navigation", Next.js will fail the build if any dynamic content is ever included in this page, ensuring that navigations to this route will never render at request time.

While "navigation" is the most restrictive form, you can also set ensureStatic to "prefetch" (to ensure links with explicit prefetching to this route only fetch static content) or "shell" (to ensure that only static content is fetched when this route is first discovered) if you need more fine-grained control.

In addition to using it on individual pages, you can also add ensureStatic to a layout to apply the same guarantees to all pages within that layout. For example, you could add ensureStatic = 'navigation' to the root layout to easily guarantee that every page navigation in your site is static:

// app/layout.tsx
export const ensureStatic = 'navigation';

export default async function RootLayout({ children }) {
// ...
}

Then, you could push it down to nested layouts if certain pages start to need dynamic content.

Many dynamic apps won't need this feature, but for optimized sites like ecommerce stores, marketing pages, or blogs, ensureStatic is a simple way to guard against unwanted request-time rendering.

Learn more about keeping pages static and the ensureStatic config.

(节选)

原文:Next.js Blog|Next.js 16.4,2026-10-07

排序方式 :

成为第一条评论!

Nobody's responded to this post yet. Add your thoughts and get the conversation going.