惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

N
Netflix TechBlog - Medium
IT之家
IT之家
博客园_首页
Hugging Face - Blog
Hugging Face - Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
美团技术团队
小众软件
小众软件
博客园 - 叶小钗
WordPress大学
WordPress大学
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - 三生石上(FineUI控件)
罗磊的独立博客
博客园 - Franky
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Last Week in AI
Last Week in AI
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
有赞技术团队
有赞技术团队
T
Tailwind CSS Blog
宝玉的分享
宝玉的分享
博客园 - 【当耐特】
月光博客
月光博客
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
酷 壳 – CoolShell
酷 壳 – CoolShell
人人都是产品经理
人人都是产品经理

Next.js Blog

How we closed 1,500 GitHub issues in one month How Turbopack chunks your JavaScript August 2026 Security Release Update: August Next.js Security Release Upcoming Next.js August Security Release Building App-like Experiences with Next.js 16.3 Making navigations instant in v0 Next.js 16.3 July 2026 Security Release Next.js Security Release and Our Next Patch Release Turbopack: What's New in Next.js 16.3 Next.js 16.3: AI Improvements Next.js 16.3: Instant Navigations Next.js Across Platforms: Adapters, OpenNext, and Our Commitments Next.js 16.2: AI Improvements Next.js 16.2 Turbopack: What's New in Next.js 16.2 Building Next.js for an agentic future Inside Turbopack: Building Faster by Building Less Next.js 16.1 Next.js Security Update: December 11, 2025 Security Advisory: CVE-2025-66478 Next.js 16 Next.js 16 (beta) Next.js 15.5 Next.js 15.4 Next.js 15.3 Building APIs with Next.js Next.js 15.2 Composable Caching with Next.js
Our Journey with Caching
Sebastian Markbåge · 2024-10-24 · via Next.js Blog

Frontend performance can be hard to get right. Even in highly optimized apps, the most common culprit by far is client-server waterfalls. When introducing Next.js App Router, we knew we wanted to solve this issue. To do that, we needed to move client-server REST fetches to the server using React Server Components in a single roundtrip. This meant the server had to sometimes be dynamic, sacrificing the great initial loading performance of Jamstack. We built partial prerendering to solve this tradeoff and have the best of both worlds.

However, along the way, the developer experience suffered due to the caching defaults and controls we provided. The default for fetch() changed to favor performance by caching by default, but quick prototyping and highly dynamic apps suffered. We didn't provide enough control over local database access that wasn't using fetch(). We had unstable_cache(), but it wasn't ergonomic. This led to the need for segment-level configs, such as export const dynamic, runtime, fetchCache, dynamicParams, revalidate = ..., as an escape hatch.

We'll continue supporting that for backward compatibility, of course. But for a moment, I'd like you to forget about all that. We think we have an idea for something simpler.

We've been cooking on a new experimental mode that builds on just two concepts: <Suspense> and use cache.

Choose your adventure

The first thing you'll notice is that when you add data to your components, you will now get an error.

To use data, cookies, headers, current time or random values, you now have a choice: do you want the data to be cached (server or client-side) or executed on every request? I'm using fetch() as an example, but this applies to any async Node API, such as databases or timers.

Dynamic

If you're still iterating or building a highly dynamic dashboard, you can wrap the component in a <Suspense> boundary. <Suspense> opts into dynamic data fetching and streaming.

You can also do this in your root layout or use loading.tsx.

This ensures that the shell of your app remains instant. You can continue adding more data inside your Page, knowing it will all be dynamic by default. Nothing is cached by default. No more hidden caches.

Static

If you're building something static and don't want to use dynamic functionality, you can use the new use cache directive.

By marking the Page with use cache, you're indicating that the entire segment should be cached. This means any data you fetch can now be cached, allowing the page to be statically rendered. No <Suspense> boundary is used for static content. You can add more data to the page, and it will all be cached.

Partial

You can also mix and match. For example, you can put use cache in your root layout to ensure it is cached. Each layout or page can be cached independently.

While using dynamic data within a specific Page:

Cached functions

When using a hybrid approach like this, it might be more convenient to add caching closer to the API calls.

You can add use cache to any async function, just like use server. Think of it as a Server Action but instead of calling a Server you're calling a Cache. It supports the same rich types of arguments and return values beyond just JSON. The cache key automatically includes any arguments and closures, so you don't need to specify a cache key manually.

Since no other data was used in this layout, it can remain static. A benefit of this approach is that if you accidentally add new dynamic data to the layout, it will trigger an error during the build, forcing you to make a new choice. If you add use cache to the entire layout, it will be cached with no error. Which approach you choose depends on your use case.

Tagging a cache

If you want to explicitly clear a cache entry by tag, you can use the new cacheTag() API inside the use cache function.

Then, just call revalidateTag('my-tag') from a Server Action as before.

Since this API can be called after data loading, you can now use data to tag your cache entries.

Defining the lifetime of a cache

If you want to control how long a particular entry or page should live in the cache, you can use the cacheLife() API:

By default, it accepts the following values:

  • "seconds"
  • "minutes"
  • "hours"
  • "days"
  • "weeks"
  • "max"

Choose a rough range that bests fits your use case. No need to specify an exact number and calculate how many seconds (or was it milliseconds?) are in a week. However, you can also specify specific values or configure your own named cache profiles.

In addition to revalidate, this API can control the stale time of the client cache as well as expire, which dictates when a Page should expire if it hasn't had much traffic for a while.

Experimental

This is still very much an experimental project. It's not production-ready yet and still has missing features and bugs. In particular, we know we need to improve the error stacks for this new type of error. However, if you're feeling adventurous, we'd love your early feedback.

We will publish a more detailed upgrade path. Aside from the early errors, the main breaking change here is undoing the default caching of fetch(). That said, we recommend experimenting only on greenfield projects at this early experimental stage. If it pans out well we hope to ship an opt-in version in a minor and make it the default in a future major.

To play with it, you must be on the canary version of Next.js:

You must also enable the experimental dynamicIO flag in next.config.ts:

Read more about use cache, cacheLife, and cacheTag in our documentation.