āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā ā š nextjs/app/guides/caching ā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā
Next.js improves your application's performance and reduces costs by caching rendering work and data requests. This page provides an in-depth look at Next.js caching mechanisms, the APIs you can use to configure them, and how they interact with each other.
Good to know: This page helps you understand how Next.js works under the hood but is not essential knowledge to be productive with Next.js. Most of Next.js' caching heuristics are determined by your API usage and have defaults for the best performance with zero or minimal configuration. If you instead want to jump to examples, start here.
Here's a high-level overview of the different caching mechanisms and their purpose:
| Mechanism | What | Where | Purpose | Duration | | ------------------------------------------- | -------------------------- | ------ | ----------------------------------------------- | ------------------------------- | | Request Memoization | Return values of functions | Server | Re-use data in a React Component tree | Per-request lifecycle | | Data Cache | Data | Server | Store data across user requests and deployments | Persistent (can be revalidated) | | Full Route Cache | HTML and RSC payload | Server | Reduce rendering cost and improve performance | Persistent (can be revalidated) | | Router Cache | RSC Payload | Client | Reduce server requests on navigation | User session or time-based |
By default, Next.js will cache as much as possible to improve performance and reduce cost. This means routes are statically rendered and data requests are cached unless you opt out. The diagram below shows the default caching behavior: when a route is statically rendered at build time and when a static route is first visited.
<Image alt="Diagram showing the default caching behavior in Next.js for the four mechanisms, with HIT, MISS and SET at build time and when a route is first visited." srcLight="/nextjs/light/caching-overview.png" srcDark="/nextjs/dark/caching-overview.png" width="1600" height="1179" />
Caching behavior changes depending on whether the route is statically or dynamically rendered, data is cached or uncached, and whether a request is part of an initial visit or a subsequent navigation. Depending on your use case, you can configure the caching behavior for individual routes and data requests.
Fetch caching is not supported in proxy. Any fetches done inside of your proxy will be uncached.
To understand how caching works in Next.js, it's helpful to understand the rendering strategies available. The rendering strategy determines when your route's HTML is generated, which directly impacts what can be cached.
With Static Rendering, routes are rendered at build time or in the background after data revalidation. The result is cached and can be reused across requests. Static routes are fully cached in the Full Route Cache.
With Dynamic Rendering, routes are rendered at request time. This happens when your route uses request-specific information like cookies, headers, or search params.
A route becomes dynamic when it uses any of these APIs:
cookiesheadersconnectiondraftModesearchParams propunstable_noStorefetch with { cache: 'no-store' }Dynamic routes are not cached in the Full Route Cache, but can still use the Data Cache for data requests.
Good to know: You can use Cache Components to mix static and dynamic rendering within the same route.
Next.js extends the fetch API to automatically memoize requests that have the same URL and options. This means you can call a fetch function for the same data in multiple places in a React component tree while only executing it once.
<Image alt="Deduplicated Fetch Requests" srcLight="/nextjs/light/deduplicated-fetch-requests.png" srcDark="/nextjs/dark/deduplicated-fetch-requests.png" width="1600" height="857" />
For example, if you need to use the same data across a route (e.g. in a Layout, Page, and multiple components), you do not have to fetch data at the top of the tree, and forward props between components. Instead, you can fetch data in the components that need it without worrying about the performance implications of making multiple requests across the network for the same data.
async function getItem() {
// The `fetch` function is automatically memoized and the result
// is cached
const res = await fetch('https://.../item/1')
return res.json()
}
// This function is called twice, but only executed the first time
const item = await getItem() // cache MISS
// The second call could be anywhere in your route
const item = await getItem() // cache HIT
async function getItem() {
// The `fetch` function is automatically memoized and the result
// is cached
const res = await fetch('https://.../item/1')
return res.json()
}
// This function is called twice, but only executed the first time
const item = await getItem() // cache MISS
// The second call could be anywhere in your route
const item = await getItem() // cache HIT
How Request Memoization Works
<Image alt="Diagram showing how fetch memoization works during React rendering." srcLight="/nextjs/light/request-memoization.png" srcDark="/nextjs/dark/request-memoization.png" width="1600" height="742" />
MISS.HIT, and the data will be returned from memory without executing the function.Good to know:
- Request memoization is a React feature, not a Next.js feature. It's included here to show how it interacts with the other caching mechanisms.
- Memoization only applies to the
GETmethod infetchrequests.- Memoization only applies to the React Component tree, this means:
- It applies to
fetchrequests ingenerateMetadata,generateStaticParams, Layouts, Pages, and other Server Components.- It doesn't apply to
fetchrequests in Route Handlers as they are not a part of the React component tree.- For cases where
fetchis not suitable (e.g. some database clients, CMS clients, or GraphQL clients), you can use the Reactcachefunction to memoize functions.
The cache lasts the lifetime of a server request until the React component tree has finished rendering.
Since the memoization is not shared across server requests and only applies during rendering, there is no need to revalidate it.
Memoization only applies to the GET method in fetch requests, other methods, such as POST and DELETE, are not memoized. This default behavior is a React optimization and we do not recommend opting out of it.
To manage individual requests, you can use the signal property from AbortController.
const { signal } = new AbortController()
fetch(url, { signal })
Next.js has a built-in Data Cache that persists the result of data fetches across incoming server requests and deployments. This is possible because Next.js extends the native fetch API to allow each request on the server to set its own persistent caching semantics.
Good to know: In the browser, the
cacheoption offetchindicates how a request will interact with the browser's HTTP cache, in Next.js, thecacheoption indicates how a server-side request will interact with the server's Data Cache.
You can use the cache and next.revalidate options of fetch to configure the caching behavior.
In development mode, fetch data is reused for Hot Module Replacement (HMR), and caching options are ignored for hard refreshes.
How the Data Cache Works
<Image alt="Diagram showing how cached and uncached fetch requests interact with the Data Cache. Cached requests are stored in the Data Cache, and memoized, uncached requests are fetched from the data source, not stored in the Data Cache, and memoized." srcLight="/nextjs/light/data-cache.png" srcDark="/nextjs/dark/data-cache.png" width="1600" height="661" />
fetch request with the 'force-cache' option is called during rendering, Next.js checks the Data Cache for a cached response.cache option defined or using { cache: 'no-store' }), the result is always fetched from the data source, and memoized.Differences between the Data Cache and Request Memoization
While both caching mechanisms help improve performance by re-using cached data, the Data Cache is persistent across incoming requests and deployments, whereas memoization only lasts the lifetime of a request.
The Data Cache is persistent across incoming requests and deployments unless you revalidate or opt-out.
Cached data can be revalidated in two ways, with:
To revalidate data at a timed interval, you can use the next.revalidate option of fetch to set the cache lifetime of a resource (in seconds).
// Revalidate at most every hour
fetch('https://...', { next: { revalidate: 3600 } })
Alternatively, you can use Route Segment Config options to configure all fetch requests in a segment or for cases where you're not able to use fetch.
How Time-based Revalidation Works
<Image alt="Diagram showing how time-based revalidation works, after the revalidation period, stale data is returned for the first request, then data is revalidated." srcLight="/nextjs/light/time-based-revalidation.png" srcDark="/nextjs/dark/time-based-revalidation.png" width="1600" height="1252" />
revalidate is called, the data will be fetched from the external data source and stored in the Data Cache.This is similar to stale-while-revalidate behavior.
Data can be revalidated on-demand by path (revalidatePath) or by cache tag (revalidateTag).
How On-Demand Revalidation Works
<Image alt="Diagram showing how on-demand revalidation works, the Data Cache is updated with fresh data after a revalidation request." srcLight="/nextjs/light/on-demand-revalidation.png" srcDark="/nextjs/dark/on-demand-revalidation.png" width="1600" height="1082" />
fetch request is called, the data will be fetched from the external data source and stored in the Data Cache.MISS again, and the data will be fetched from the external data source and stored in the Data Cache.If you do not want to cache the response from fetch, you can do the following:
let data = await fetch('https://api.vercel.app/blog', { cache: 'no-store' })
Related terms:
You may see the terms Automatic Static Optimization, Static Site Generation, or Static Rendering being used interchangeably to refer to the process of rendering and caching routes of your application at build time.
Next.js automatically renders and caches routes at build time. This is an optimization that allows you to serve the cached route instead of rendering on the server for every request, resulting in faster page loads.
To understand how the Full Route Cache works, it's helpful to look at how React handles rendering, and how Next.js caches the result:
On the server, Next.js uses React's APIs to orchestrate rendering. The rendering work is split into chunks: by individual routes segments and Suspense boundaries.
Each chunk is rendered in two steps:
This means we don't have to wait for everything to render before caching the work or sending a response. Instead, we can stream a response as work is completed.
What is the React Server Component Payload?
The React Server Component Payload is a compact binary representation of the rendered React Server Components tree. It's used by React on the client to update the browser's DOM. The React Server Component Payload contains:
- The rendered result of Server Components
- Placeholders for where Client Components should be rendered and references to their JavaScript files
- Any props passed from a Server Component to a Client Component
To learn more, see the Server Components documentation.
<Image alt="Default behavior of the Full Route Cache, showing how the React Server Component Payload and HTML are cached on the server for statically rendered routes." srcLight="/nextjs/light/full-route-cache.png" srcDark="/nextjs/dark/full-route-cache.png" width="1600" height="888" />
The default behavior of Next.js is to cache the rendered result (React Server Component Payload and HTML) of a route on the server. This applies to statically rendered routes at build time, or during revalidation.
At request time, on the client:
The React Server Component Payload is stored in the client-side Router Cache - a separate in-memory cache, split by individual route segment. This Router Cache is used to improve the navigation experience by storing previously visited routes and prefetching future routes.
On subsequent navigations or during prefetching, Next.js will check if the React Server Components Payload is stored in the Router Cache. If so, it will skip sending a new request to the server.
If the route segments are not in the cache, Next.js will fetch the React Server Components Payload from the server, and populate the Router Cache on the client.
Whether a route is cached or not at build time depends on whether it's statically or dynamically rendered. Static routes are cached by default, whereas dynamic routes are rendered at request time, and not cached.
This diagram shows the difference between statically and dynamically rendered routes, with cached and uncached data:
<Image alt="How static and dynamic rendering affects the Full Route Cache. Static routes are cached at build time or after data revalidation, whereas dynamic routes are never cached" srcLight="/nextjs/light/static-and-dynamic-routes.png" srcDark="/nextjs/dark/static-and-dynamic-routes.png" width="1600" height="1314" />
Learn more about static and dynamic rendering.
By default, the Full Route Cache is persistent. This means that the render output is cached across user requests.
There are two ways you can invalidate the Full Route Cache:
You can opt out of the Full Route Cache, or in other words, dynamically render components for every incoming request, by:
dynamic = 'force-dynamic' or revalidate = 0 route segment config options: This will skip the Full Route Cache and the Data Cache. Meaning components will be rendered and data fetched on every incoming request to the server. The Router Cache will still apply as it's a client-side cache.fetch request that is not cached, this will opt the route out of the Full Route Cache. The data for the specific fetch request will be fetched for every incoming request. Other fetch requests that explicitly enable caching will still be cached in the Data Cache. This allows for a hybrid of cached and uncached data.Next.js has an in-memory client-side router cache that stores the RSC payload of route segments, split by layouts, loading states, and pages.
When a user navigates between routes, Next.js caches the visited route segments and prefetches the routes the user is likely to navigate to. This results in instant back/forward navigation, no full-page reload between navigations, and preservation of browser state and React state in shared layouts.
With the Router Cache:
staleTimes config option.{/* TODO: Update diagram to match v15 behavior */}
Good to know: This cache specifically applies to Next.js and Server Components, and is different to the browser's bfcache, though it has a similar result.
The cache is stored in the browser's temporary memory. Two factors determine how long the router cache lasts:
prefetch={null} or unspecified): not cached for dynamic pages, 5 minutes for static pages.prefetch={true} or router.prefetch): 5 minutes for both static & dynamic pages.While a page refresh will clear all cached segments, the automatic invalidation period only affects the individual segment from the time it was prefetched.
Good to know: The experimental
staleTimesconfig option can be used to adjust the automatic invalidation times mentioned above.
There are two ways you can invalidate the Router Cache:
revalidatePath) or by cache tag with (revalidateTag)cookies.set or cookies.delete invalidates the Router Cache to prevent routes that use cookies from becoming stale (e.g. authentication).router.refresh will invalidate the Router Cache and make a new request to the server for the current route.As of Next.js 15, page segments are opted out by default.
Good to know: You can also opt out of prefetching by setting the
prefetchprop of the<Link>component tofalse.
When configuring the different caching mechanisms, it's important to understand how they interact with each other:
revalidatePath or revalidateTag in a Server Action.The following table provides an overview of how different Next.js APIs affect caching:
| API | Router Cache | Full Route Cache | Data Cache | React Cache |
| ----------------------------------------------------------------------- | -------------------------- | --------------------- | --------------------- | -------------------- |
| <Link prefetch> | Cache | | | |
| router.prefetch | Cache | | | |
| router.refresh | Revalidate | | | |
| fetch | | | Cache | Cache (GET and HEAD) |
| fetch options.cache | | | Cache or Opt out | |
| fetch options.next.revalidate | | Revalidate | Revalidate | |
| fetch options.next.tags | | Cache | Cache | |
| revalidateTag | Revalidate (Server Action) | Revalidate | Revalidate | |
| revalidatePath | Revalidate (Server Action) | Revalidate | Revalidate | |
| const revalidate | | Revalidate or Opt out | Revalidate or Opt out | |
| const dynamic | | Cache or Opt out | Cache or Opt out | |
| cookies | Revalidate (Server Action) | Opt out | | |
| headers, searchParams | | Opt out | | |
| generateStaticParams | | Cache | | |
| React.cache | | | | Cache |
| unstable_cache | | | Cache | |
<Link>By default, the <Link> component automatically prefetches routes from the Full Route Cache and adds the React Server Component Payload to the Router Cache.
To disable prefetching, you can set the prefetch prop to false. But this will not skip the cache permanently, the route segment will still be cached client-side when the user visits the route.
Learn more about the <Link> component.
router.prefetchThe prefetch option of the useRouter hook can be used to manually prefetch a route. This adds the React Server Component Payload to the Router Cache.
See the useRouter hook API reference.
router.refreshThe refresh option of the useRouter hook can be used to manually refresh a route. This completely clears the Router Cache, and makes a new request to the server for the current route. refresh does not affect the Data or Full Route Cache.
The rendered result will be reconciled on the client while preserving React state and browser state.
See the useRouter hook API reference.
fetchData returned from fetch is not automatically cached in the Data Cache.
By default, when no cache or next.revalidate options are provided:
See the fetch API Reference for more options.
fetch options.cacheYou can opt individual fetch into caching by setting the cache option to force-cache:
// Opt into caching
fetch(`https://...`, { cache: 'force-cache' })
See the fetch API Reference for more options.
fetch options.next.revalidateYou can use the next.revalidate option of fetch to set the revalidation period (in seconds) of an individual fetch request. This will revalidate the Data Cache, which in turn will revalidate the Full Route Cache. Fresh data will be fetched, and components will be re-rendered on the server.
// Revalidate at most after 1 hour
fetch(`https://...`, { next: { revalidate: 3600 } })
See the fetch API reference for more options.
fetch options.next.tags and revalidateTagNext.js has a cache tagging system for fine-grained data caching and revalidation.
fetch or unstable_cache, you have the option to tag cache entries with one or more tags.revalidateTag to purge the cache entries associated with that tag.For example, you can set a tag when fetching data:
// Cache data with a tag
fetch(`https://...`, { next: { tags: ['a', 'b', 'c'] } })
Then, call revalidateTag with a tag to purge the cache entry:
// Revalidate entries with a specific tag
revalidateTag('a')
There are two places you can use revalidateTag, depending on what you're trying to achieve:
revalidatePathrevalidatePath allows you manually revalidate data and re-render the route segments below a specific path in a single operation. Calling the revalidatePath method revalidates the Data Cache, which in turn invalidates the Full Route Cache.
revalidatePath('/')
There are two places you can use revalidatePath, depending on what you're trying to achieve:
See the revalidatePath API reference for more information.
revalidatePathvs.router.refresh:Calling
router.refreshwill clear the Router cache, and re-render route segments on the server without invalidating the Data Cache or the Full Route Cache.The difference is that
revalidatePathpurges the Data Cache and Full Route Cache, whereasrouter.refresh()does not change the Data Cache and Full Route Cache, as it is a client-side API.
Dynamic APIs like cookies and headers, and the searchParams prop in Pages depend on runtime incoming request information. Using them will opt a route out of the Full Route Cache, in other words, the route will be dynamically rendered.
cookiesUsing cookies.set or cookies.delete in a Server Action invalidates the Router Cache to prevent routes that use cookies from becoming stale (e.g. to reflect authentication changes).
See the cookies API reference.
The Route Segment Config options can be used to override the route segment defaults or when you're not able to use the fetch API (e.g. database client or 3rd party libraries).
The following Route Segment Config options will opt out of the Full Route Cache:
const dynamic = 'force-dynamic'This config option will opt all fetches out of the Data Cache (i.e. no-store):
const fetchCache = 'default-no-store'See the fetchCache to see more advanced options.
See the Route Segment Config documentation for more options.
generateStaticParamsFor dynamic segments (e.g. app/blog/[slug]/page.js), paths provided by generateStaticParams are cached in the Full Route Cache at build time. At request time, Next.js will also cache paths that weren't known at build time the first time they're visited.
To statically render all paths at build time, supply the full list of paths to generateStaticParams:
export async function generateStaticParams() {
const posts = await fetch('https://.../posts').then((res) => res.json())
return posts.map((post) => ({
slug: post.slug,
}))
}
To statically render a subset of paths at build time, and the rest the first time they're visited at runtime, return a partial list of paths:
export async function generateStaticParams() {
const posts = await fetch('https://.../posts').then((res) => res.json())
// Render the first 10 posts at build time
return posts.slice(0, 10).map((post) => ({
slug: post.slug,
}))
}
To statically render all paths the first time they're visited, return an empty array (no paths will be rendered at build time) or utilize export const dynamic = 'force-static':
export async function generateStaticParams() {
return []
}
Good to know: You must return an array from
generateStaticParams, even if it's empty. Otherwise, the route will be dynamically rendered.
export const dynamic = 'force-static'
To disable caching at request time, add the export const dynamicParams = false option in a route segment. When this config option is used, only paths provided by generateStaticParams will be served, and other routes will 404 or match (in the case of catch-all routes).
cache functionThe React cache function allows you to memoize the return value of a function, allowing you to call the same function multiple times while only executing it once.
fetch requests using the GET or HEAD methods are automatically memoized, so you do not need to wrap it in React cache. However, for other fetch methods, or when using data fetching libraries (such as some database, CMS, or GraphQL clients) that don't inherently memoize requests, you can use cache to manually memoize data requests.
import { cache } from 'react'
import db from '@/lib/db'
export const getItem = cache(async (id: string) => {
const item = await db.item.findUnique({ id })
return item
})
import { cache } from 'react'
import db from '@/lib/db'
export const getItem = cache(async (id) => {
const item = await db.item.findUnique({ id })
return item
})
ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā