nextjs-caching

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Next.js Caching Expert Guidance

Next.js缓存专业指导

This skill provides expert-level guidance on Next.js caching behavior, focusing on the
"use cache"
directive, revalidation strategies, and Incremental Static Regeneration (ISR) patterns.
本技能提供关于Next.js缓存行为的专业级指导,重点聚焦
"use cache"
指令、重新验证策略以及增量静态再生(ISR)模式。

Core Mental Models

核心思维模型

The "use cache" Directive

"use cache"指令

The
"use cache"
directive marks a component or function as cacheable—it doesn't immediately cache anything. Caching happens at build time when Next.js writes the output to the cache store. This is a fundamental distinction that affects how you reason about cache behavior.
"use cache"
指令标记组件或函数为可缓存的,但不会立即进行缓存操作。缓存会在构建阶段发生,当Next.js将输出写入缓存存储时。这是一个基础的区别,会影响你对缓存行为的理解方式。

Automatic Static Rendering

自动静态渲染

Next.js automatically renders from top to bottom as deep as possible until it encounters something dynamic (like uncached data fetches). It then creates a "dynamic hole" for that content. You don't need to add
"use cache"
to every page—the framework handles partial static rendering automatically. Cached functions are NOT considered dynamic, so they don't create holes.
Next.js会自动从上到下尽可能深度地进行渲染,直到遇到动态内容(比如未缓存的数据获取)。然后它会为该内容创建一个“动态缺口”。你不需要为每个页面添加
"use cache"
——框架会自动处理部分静态渲染。缓存的函数不会被视为动态内容,因此不会创建缺口。

Two-Phase Rendering

两阶段渲染

Two renders occur during the build process:
  1. Warmup render (prospective render): Detects if dynamic APIs are used. Anything that doesn't resolve in a microtask is considered dynamic.
  2. Final render: Captures the actual output for the pre-rendered result.
构建过程中会发生两次渲染:
  1. 预热渲染(预渲染):检测是否使用了动态API。任何无法在微任务中解析的内容都会被视为动态内容。
  2. 最终渲染:捕获预渲染结果的实际输出。

Key Behaviors

关键行为

ISR-Like Behavior

类ISR行为

Adding
"use cache"
to a page component makes it work like ISR—the entire output gets cached instead of having dynamic holes. Caches cannot be partial at the page level. To make a route ISR-like, add
"use cache"
to the main exported component (either at the top of the file or on the component itself).
页面组件上添加
"use cache"
会使其表现得像ISR——整个输出会被缓存,而不是留下动态缺口。页面级别的缓存不能是部分的。要让路由实现类ISR行为,需要在主导出组件上添加
"use cache"
(可以在文件顶部或组件本身添加)。

Layout vs Page Caching

布局与页面缓存的区别

Setting
"use cache"
in a layout without setting it on the page does NOT make the page static. Each route segment controls its own caching behavior independently.
在布局中设置
"use cache"
但不在页面上设置,并不会使页面变为静态。每个路由段独立控制自己的缓存行为。

Suspense Boundaries with "use cache"

结合Suspense边界使用"use cache"

When you use
"use cache"
on a component with a Suspense boundary (containing components that fetch data), it works like ISR. The first request triggers the Suspense boundary, shows content, then caches the result for subsequent requests. If you want the Suspense boundary to show dynamic content every time, extract static parts into separate components with their own
"use cache"
directives (or use parallel routes).
当在带有Suspense边界(包含获取数据的组件)的组件上使用
"use cache"
时,其表现类似ISR。首次请求会触发Suspense边界,显示内容,然后为后续请求缓存结果。如果你希望Suspense边界每次都显示动态内容,可以将静态部分提取到带有各自
"use cache"
指令的独立组件中(或使用并行路由)。

Critical Distinctions

重要区别

Revalidation APIs

重新验证API

  • revalidatePath
    is conceptually similar to
    revalidateTag
    , with the argument being path-like
  • revalidateTag
    revalidates in a stale-while-revalidate manner when used in server actions
  • updateTag
    works as "read-your-own-writes" by purging the previous cache immediately, but cannot be used in route handlers
  • revalidatePath
    在概念上与
    revalidateTag
    类似,只是参数是路径形式
  • 在服务器操作中使用
    revalidateTag
    时,会以stale-while-revalidate的方式进行重新验证
  • updateTag
    通过立即清除之前的缓存来实现“读自己的写入”,但不能在路由处理器中使用

Cache Persistence

缓存持久性

  • unstable_cache
    persists across deployments
  • use cache: remote
    does NOT persist across deployments
  • Choose based on whether you need deployment-persistent caching
  • unstable_cache
    在部署之间会持久化
  • use cache: remote
    在部署之间不会持久化
  • 根据是否需要跨部署持久化缓存来选择使用

Common Patterns

常见模式

Partial Page Caching

部分页面缓存

To cache only parts of a page while keeping others dynamic:
  • Leave the page without
    "use cache"
  • Add
    "use cache"
    to individual components
  • Wrap dynamic components in Suspense boundaries as needed
  • Alternative: Use parallel routes for the same effect
要仅缓存页面的部分内容,同时保持其他部分动态:
  • 不为页面添加
    "use cache"
  • 为单个组件添加
    "use cache"
  • 根据需要将动态组件包裹在Suspense边界中
  • 替代方案:使用并行路由实现相同效果

Sharing Cached Values

共享缓存值

When you need a cached value from a layout in a page, cache the function output instead of the component. Call the function again in the page to retrieve the cached value.
当需要在页面中使用布局中的缓存值时,缓存函数输出而不是组件。在页面中再次调用该函数以获取缓存值。

Build-Time Snapshots

构建时快照

Every cacheable function gets a snapshot when called at build time. Using a
"use cache"
'd function in a dynamic component only guarantees a cache hit if that snapshot was captured at build time. Otherwise, it serves from in-memory cache.
每个可缓存函数在构建时被调用时都会生成一个快照。在动态组件中使用带有
"use cache"
的函数,只有当该快照在构建时被捕获时,才能保证缓存命中。否则,将从内存缓存中提供内容。

API & Configuration Details

API与配置细节

Dynamic API Replacement

动态API替代

Use
connection()
as a replacement for
unstable_noStore()
.
使用
connection()
替代
unstable_noStore()

Short Cache Behavior

短缓存行为

Caches with a
stale
configuration of less than 30 seconds are considered "short cache" and won't be included in runtime prefetch.
stale
配置小于30秒的缓存被视为“短缓存”,不会被包含在运行时预取中。

unstable_cache Functions

unstable_cache函数

unstable_cache
functions are considered instant (they don't create dynamic holes).
unstable_cache
函数被视为即时的(它们不会创建动态缺口)。

generateStaticParams Requirements

generateStaticParams要求

  • Export at least one param in
    generateStaticParams
    to actually generate a static shell for that route
  • Without
    generateStaticParams
    , dynamic pages fail because there's no Suspense boundary when reading params
  • Workaround: Add a
    loading.tsx
    file or wrap the body in an empty Suspense boundary
  • For ISR behavior on dynamic pages, always export at least one param from
    generateStaticParams
  • If no real param exists, return a placeholder and handle that case in component rendering
  • 必须在
    generateStaticParams
    中导出至少一个参数,才能为该路由生成实际的静态外壳
  • 如果没有
    generateStaticParams
    ,动态页面会失败,因为读取参数时没有Suspense边界
  • 解决方法:添加
    loading.tsx
    文件或将主体包裹在空的Suspense边界中
  • 要在动态页面上实现ISR行为,始终从
    generateStaticParams
    导出至少一个参数
  • 如果没有实际参数,返回一个占位符,并在组件渲染中处理这种情况

Deployment Architecture

部署架构

The proxy that returns the static shell runs on the edge. It returns the shell immediately and continues the request for dynamic content. If a region goes down, the proxy continues working.
返回静态外壳的代理在边缘运行。它会立即返回外壳,并继续处理动态内容的请求。如果某个区域宕机,代理仍会继续工作。

Verification

验证

Static pages sometimes show as
ppr
in the build log. The most reliable way to verify a page is static is checking that
x-nextjs-cache
header equals
HIT
in the document request.
静态页面有时在构建日志中显示为
ppr
。验证页面是否为静态的最可靠方法是检查文档请求中的
x-nextjs-cache
头是否等于
HIT

References

参考资料

For comprehensive details, code examples, and deep-dives into each topic:
  • references/detailed-guide.md — Full expanded guidance with all insights organized by topic. Consult this when you need detailed explanations, edge cases, or specific implementation patterns.
如需全面的细节、代码示例以及每个主题的深度解析:
  • references/detailed-guide.md —— 完整的扩展指导,按主题组织所有见解。当你需要详细解释、边缘情况或特定实现模式时,请参考此文档。