Caching
Learn how to cache data and UI in Next.js
This page covers caching with Cache Components, enabled by setting cacheComponents: true in your next.config.ts file. If you're not using Cache Components, see the Caching and Revalidating (Previous Model) guide.
Caching is a technique for storing the result of data fetching and other computations so that future requests for the same data can be served faster, without doing the work again.
Enabling Cache Components
You can enable Cache Components by adding the cacheComponents option to your Next config file:
Good to know: When Cache Components is enabled, GET Route Handlers follow the same prerendering model as pages. See Route Handlers with Cache Components for details.
Usage
The use cache directive caches the return value of async functions and components. You can apply it at two levels:
- Data-level: Cache a function that fetches or computes data (e.g.,
getProducts(),getUser(id)) - UI-level: Cache an entire component or page (e.g.,
async function BlogPosts())
Arguments and any closed-over values from parent scopes automatically become part of the cache key, which means different inputs will produce separate cache entries. This enables personalized or parameterized cached content. See serialization requirements and constraints for details on what can be cached and how arguments work.
Data-level caching
To cache an asynchronous function that fetches data, add the use cache directive at the top of the function body:
Data-level caching is useful when the same data is used across multiple components, or when you want to cache the data independently from the UI.
UI-level caching
To cache an entire component, page, or layout, add the use cache directive at the top of the component or page body:
If you add "use cache" at the top of a file, all exported functions in the file will be cached.
Streaming uncached data
For components that fetch data from an asynchronous source such as an API, a database, or any other async operation, and require fresh data on every request, do not use "use cache".
Instead, wrap the component in <Suspense> and provide a fallback UI. At request time, React renders the fallback first, then streams in the resolved content once the async work completes.
The fallback (<p>Loading posts...</p>) is included in the static shell, while the component's content streams in at request time.
Working with runtime APIs
Request-time APIs require information that is only available when a user makes a request. These include:
cookies- User's cookie dataheaders- Request headerssearchParams- URL query parametersparams- Dynamic route parameters (unless at least one sample is provided viagenerateStaticParams).
Components that access runtime APIs should be wrapped in <Suspense>:
Passing runtime values to cached functions
You can extract values from runtime APIs and pass them as arguments to cached functions:
At request time, CachedContent executes if no matching cache entry is found, and stores the result for future requests with the same sessionId.
Working with non-deterministic operations
Operations like Math.random(), Date.now(), or crypto.randomUUID() produce different values each time they execute. Cache Components requires you to explicitly handle these.
To generate unique values per request, defer to request time by calling connection() before these operations, and wrap the component in <Suspense>:
Alternatively, you can cache the result so all users see the same value until revalidation:
Working with deterministic operations
Operations like synchronous I/O, module imports, and pure computations can complete during prerendering. Components using only these operations have their rendered output automatically included in the static HTML shell.
How rendering works
At build time, Next.js renders your route's component tree. How each component is handled depends on the APIs it uses:
use cache: the result is cached and included in the static shell<Suspense>: fallback UI is included in the static shell while the content streams at request time- Deterministic operations: like pure computations and module imports are automatically included in the static shell
This generates a static shell consisting of HTML for initial page loads and a serialized RSC Payload for client-side navigation, ensuring the browser receives fully rendered content instantly whether users navigate directly to the URL or transition from another page.

This rendering approach is called Partial Prerendering (PPR), and it's the default behavior with Cache Components.
You can verify that a route was fully prerendered by checking the build output summary. Alternatively, see what content was added to the static shell of any page by viewing the page source in your browser.

Next.js requires you to explicitly handle components that can't complete during prerendering. If they aren't wrapped in <Suspense> or marked with use cache, you'll see an Uncached data was accessed outside of <Suspense> error during development and build time.
🎥 Watch: Why Partial Prerendering and how it works → YouTube (10 minutes).
Opting out of the static shell
Placing a <Suspense> boundary with an empty fallback above the document body in your Root Layout causes the entire app to defer to request time. Because the fallback is empty, there is no static shell to send immediately, so every request blocks until the page is fully rendered. To limit this to specific routes, use multiple root layouts.
Good to know: This same pattern applies when generateViewport accesses uncached dynamic data. See Viewport with Cache Components for a detailed example.
Putting it all together
Here's a complete example showing static content, cached dynamic content, and streaming dynamic content working together on a single page:
During prerendering, the header (static) and blog posts (cached with use cache) become part of the static shell along with the fallback UI for user preferences. Only the personalized preferences stream in at request time. When an admin publishes a new post, the updateTag call immediately expires the blog posts cache so the next visitor sees it.
Good to know: generateMetadata and generateViewport track runtime data access separately from the page. See Metadata with Cache Components and Viewport with Cache Components for how to handle this.

