Caching Data
Next.js has built-in support for caching data, both on a per-request basis (recommended) or for an entire route segment.


Per-request Caching
fetch()
By default, all fetch()
requests are cached and deduplicated automatically. This means that if you make the same request twice, the second request will reuse the result from the first request.
async function getComments() {
const res = await fetch('https://...'); // The result is cached
return res.json();
}
// This function is called twice, but the result is only fetched once
const comments = await getComments(); // cache MISS
// The second call could be anywhere in your application
const comments = await getComments(); // cache HIT
Requests are not cached if:
- Dynamic methods (
next/headers
,export const POST
, or similar) are used and the fetch is aPOST
request (or usesAuthorization
orcookie
headers) fetchCache
is configured to skip cache by defaultrevalidate: 0
orcache: 'no-store'
is configured on individualfetch
Requests made using fetch
can specify a revalidate
option to control the revalidation frequency of the request.
export default async function Page() {
// revalidate this data every 10 seconds at most
const res = await fetch('https://...', { next: { revalidate: 10 } });
const data = res.json();
// ...
}
React cache()
React allows you to cache()
and deduplicate requests, memoizing the result of the wrapped function call. The same function called with the same arguments will reuse a cached value instead of re-running the function.
import { cache } from 'react';
export const getUser = cache(async (id: string) => {
const user = await db.user.findUnique({ id });
return user;
});
import { getUser } from '@utils/getUser';
export default async function UserLayout({ params: { id } }) {
const user = await getUser(id);
// ...
}
import { getUser } from '@utils/getUser';
export default async function Page({
params: { id },
}: {
params: { id: string };
}) {
const user = await getUser(id);
// ...
}
Although the getUser()
function is called twice in the example above, only one query will be made to the database. This is because getUser()
is wrapped in cache()
, so the second request can reuse the result from the first request.
Good to know:
fetch()
caches requests automatically, so you don't need to wrap functions that usefetch()
withcache()
. See automatic request deduping for more information.- In this new model, we recommend fetching data directly in the component that needs it, even if you're requesting the same data in multiple components, rather than passing the data between components as props.
- We recommend using the
server-only
package to make sure server data fetching functions are never used on the client.
POST
requests and cache()
POST
requests are automatically deduplicated when using fetch
– unless they are inside of POST
Route Handler or come after reading headers()
/cookies()
. For example, if you are using GraphQL and POST
requests in the above cases, you can use cache
to deduplicate requests. The cache
arguments must be flat and only include primitives. Deep objects won't match for deduplication.
import { cache } from 'react';
export const getUser = cache(async (id: string) => {
const res = await fetch('...', { method: 'POST', body: '...' });
// ...
});
Preload pattern with cache()
As a pattern, we suggest optionally exposing a preload()
export in utilities or components that do data fetching.
import { getUser } from '@utils/getUser';
export const preload = (id: string) => {
// void evaluates the given expression and returns undefined
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/void
void getUser(id);
};
export default async function User({ id }: { id: string }) {
const result = await getUser(id);
// ...
}
By calling preload
, you can eagerly start fetching data you're likely going to need.
import User, { preload } from '@components/User';
export default async function Page({
params: { id },
}: {
params: { id: string };
}) {
preload(id); // starting loading the user data now
const condition = await fetchCondition();
return condition ? <User id={id} /> : null;
}
Good to know:
- The
preload()
function can have any name. It's a pattern, not an API.- This pattern is completely optional and something you can use to optimize on a case-by-case basis. This pattern is a further optimization on top of parallel data fetching. Now you don't have to pass promises down as props and can instead rely on the preload pattern.
Combining cache
, preload
, and server-only
You can combine the cache
function, the preload
pattern, and the server-only
package to create a data fetching utility that can be used throughout your app.
import { cache } from 'react';
import 'server-only';
export const preload = (id: string) => {
void getUser(id);
};
export const getUser = cache(async (id: string) => {
// ...
});
With this approach, you can eagerly fetch data, cache responses, and guarantee that this data fetching only happens on the server.
The getUser.ts
exports can be used by layouts, pages, or components to give them control over when a user's data is fetched.
Segment-level Caching
Note: We recommend using per-request caching for improved granularity and control over caching.
Segment-level caching allows you to cache and revalidate data used in route segments.
This mechanism allows different segments of a path to control the cache lifetime of the entire route. Each page.tsx
and layout.tsx
in the route hierarchy can export a revalidate
value that sets the revalidation time for the route.
export const revalidate = 60; // revalidate this segment every 60 seconds
Good to know:
- If a page, layout, and fetch request inside components all specify a
revalidate
frequency, the lowest value of the three will be used.- Advanced: You can set
fetchCache
to'only-cache'
or'force-cache'
to ensure that allfetch
requests opt into caching but the revalidation frequency might still be lowered by individualfetch
requests. SeefetchCache
for more information.