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

推荐订阅源

WordPress大学
WordPress大学
www.infosecurity-magazine.com
www.infosecurity-magazine.com
博客园 - 聂微东
博客园 - 【当耐特】
Last Week in AI
Last Week in AI
量子位
S
SegmentFault 最新的问题
Hugging Face - Blog
Hugging Face - Blog
B
Blog RSS Feed
V
V2EX
酷 壳 – CoolShell
酷 壳 – CoolShell
雷峰网
雷峰网
GbyAI
GbyAI
Jina AI
Jina AI
宝玉的分享
宝玉的分享
腾讯CDC
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
D
Docker
博客园_首页
N
News and Events Feed by Topic
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Help Net Security
Help Net Security
Recent Commits to openclaw:main
Recent Commits to openclaw:main
C
Cisco Blogs
F
Fortinet All Blogs
SecWiki News
SecWiki News
AI
AI
S
Schneier on Security
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
The Last Watchdog
The Last Watchdog
Martin Fowler
Martin Fowler
A
About on SuperTechFans
T
Troy Hunt's Blog
P
Proofpoint News Feed
Blog — PlanetScale
Blog — PlanetScale
Hacker News: Ask HN
Hacker News: Ask HN
F
Full Disclosure
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
I
InfoQ
S
Security @ Cisco Blogs
Project Zero
Project Zero
Simon Willison's Weblog
Simon Willison's Weblog
C
Cyber Attacks, Cyber Crime and Cyber Security
J
Java Code Geeks
N
News | PayPal Newsroom
IT之家
IT之家
大猫的无限游戏
大猫的无限游戏
H
Hacker News: Front Page

Next.js Blog

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 Next.js 15.1 Our Journey with Caching Next.js 15 Turbopack Dev is Now Stable Next.js 15 RC 2 Next.js 15 RC Next.js 14.2 Next.js 14.1 Next.js 14 How to Think About Security in Next.js Next.js 13.5 Next.js App Router Update Next.js 13.4 Next.js 13.3 Next.js 13.2 Next.js 13.1 Next.js 13 Next.js 12.3 Next.js 12.2 Layouts RFC Next.js 12.1 Next.js 12 Next.js 11.1 Next.js 11 Next.js 10.2 Next.js 10.1 Incrementally Adopting Next.js Next.js 10 Next.js 9.5 Next.js 9.4 Next.js 9.3 Next.js 9.2 Next.js 9.1.7 Introducing Create Next App Next.js 9.1 Next.js 9.0.7 Next.js 9 Next.js 8.1 Next.js 8.0.4 Styling Next.js with Styled JSX Next.js 8 Webpack Memory Improvements Next.js 8 Next.js 7 Next.js 6.1 Next.js 6 and Nextjs.org Next.js 5.1: Faster Page Resolution, Environment Config & More Next.js 5: Universal Webpack, CSS Imports, Plugins and Zones
Composable Caching with Next.js
Lee Robinson · 2025-01-03 · via Next.js Blog
Back to Blog

Friday, January 3rd 2025

Posted by

We’re working on a simple and powerful caching model for Next.js. In a previous post, we talked about our journey with caching and how we’ve arrived at the 'use cache' directive.

This post will discuss the API design and benefits of 'use cache'.

What is 'use cache'?

'use cache' makes your application faster by caching data or components as needed.

It’s a JavaScript “directive”—a string literal you add in your code—which signals to the Next.js compiler to enter a different “boundary”. For example, going from the server to the client.

This is a similar idea to React directives like 'use client' and 'use server'. Directives are compiler instructions that define where code should run, allowing the framework to optimize and orchestrate individual pieces for you.

How does it work?

Let’s start with a simple example:

Behind the scenes, Next.js transforms this code into a server function due to the 'use cache' directive. During compilation, the “dependencies” of this cache entry are found and used as part of the cache key.

For example, id becomes part of the cache key. If we call getUser(1) multiple times, we return the memoized output from the cached server function. Changing this value will create a new entry in the cache.

Let’s look at an example using the cached function in a server component with a closure.

This example is more difficult. Can you spot all the dependencies which need to be part of the cache key?

The arguments index and limit make sense—if these values change, we select a different slice of the notifications. However, what about the user id? It’s value is coming from the parent component.

The compiler is able to understand getNotifications also depends on id, and it’s value is automatically included in the cache key. This prevents an entire category of caching issues from incorrect or missing dependencies in the cache key.

Why not use a cache function?

Let’s revisit the last example. Could we instead use a cache() function instead of a directive?

A cache() function wouldn’t be able to look into the closure and see the id value should be part of the cache key. You would need to manually specify that id is part of your key. If you forget to do so, or do it incorrectly, you risk cache collisions or stale data.

Closures can capture all sorts of local variables. A naive approach could accidentally bake in (or omit) variables you didn’t intend to. That can lead to caching the wrong data, or it might risk cache poisoning if sensitive info bleeds into the cache key.

'use cache' gives the compiler enough context to handle closures safely and produce cache keys correctly. A runtime-only solution, like cache(), would require you to do everything manually—and it’s easy to make mistakes. By contrast, a directive can be statically analyzed to reliably handle all your dependencies under the hood.

How are non-serialized input values handled?

We have two different types of input values to cache:

  • Serializable: Here, “serializable” means an input can be turned into a stable, string-based format without losing meaning. While many people think first of JSON.stringify, we actually use React’s serialization (e.g., via Server Components) to handle a broader range of inputs—including promises, circular data structures, and other complex objects. This goes beyond what plain JSON can do.
  • Non-serializable: These inputs are not part of the cache key. When we attempt to cache these values, we return a server "reference". This reference is then used by Next.js to restore back the original value at runtime.

Let’s say we remembered to include id in the cache key:

This works if the input values can be serialized. But if id was a React element or more complex value, we’d have to manually serialize the input keys. Consider a server component which fetches the current user based on an id prop:

Let’s step through how this works:

  1. During compilation, Next.js sees the 'use cache' directive and transforms the code to create a special server function that supports caching. No caching happens during compilation, but rather Next.js is setting up the mechanism needed for runtime caching.
  2. When your code calls the "cache function", Next.js serializes the function's arguments. Anything that is not directly serializable, like JSX, is replaced with a "reference" placeholder.
  3. Next.js checks whether a cached result exists for the given serialized arguments. If no result is found, the function computes the new value to cache.
  4. After the function finishes, the return value is serialized. Non-serializable parts of the return value are turned back into references.
  5. The code which called the cache function deserializes the output and evaluates the references. This allows Next.js to swap the references with their actual objects or values, meaning non-serializable inputs like children can keep their original, uncached values.

This means we can safely cache just the <Profile> component and not the children. On subsequent renders, getUser() is not called again. The value of children might be dynamic or a separately cached element with a different cache life. This is composable caching.

This seems familiar…

If you’re thinking “that feels like the same model of server and client composition”—you’re absolutely right. This is sometimes called the “donut” pattern:

  • The outer part of the donut is a server component that handles data fetching or heavy logic.
  • The hole in the middle is a child component that might have some interactivity

'use cache' is the same. The donut is the outer component’s cached value and the hole is the references that get filled in at runtime. This is why changing children does not invalidate the entire cached output. The children are just some reference that gets filled in later.

What about tagging and invalidation?

You can define the life of the cache with different profiles. We include a set of default profiles, but you can define your own custom values if desired.

To invalidate a specific cache entry, you can tag the cache and then call revalidateTag(). One powerful pattern is that you can tag the cache after you have fetched your data (e.g. from a CMS):

Simple and powerful

Our goal with 'use cache' is to make authoring caching logic simple and powerful.

  • Simple: You can create cache entries with local reasoning. You don’t need to worry about global side effects, like forgotten cache key entries or unintended changes to other parts of your codebase.
  • Powerful: You can cache more than just statically analyzable code. For example, values which might change at runtime, yet you still want to cache the output result after it’s been evaluated.

'use cache is still experimental inside Next.js. We’d love your early feedback as you test it out.

Learn more in the documentation.