Caching Data
Next.js has built-in support for caching data, both on a per-request basis (recommended) or for an entire route segment.
By default, all fetch() requests are cached and deduplicated automatically.
Requests are not cached if:
- Dynamic methods (
next/headers,export const POST, or similar) are used and the fetch is aPOSTrequest (or usesAuthorizationorcookieheaders) fetchCacheis configured to skip cache by defaultrevalidate: 0orcache: 'no-store'is configured on individualfetch
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.
utils/getUser.ts
import { cache } from 'react';
export const getUser = cache(async (id: string) => {
const user = await db.user.findUnique({ id });
return user;
});
GraphQL and cache()
POST requests are automatically deduplicated when using fetch – unless they are inside of POST Route Handler or come after reading headers()/cookies(). 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.
utils/getUser.ts
import { cache } from 'react';
export const getUser = cache(async (id: string) => {
const res = await fetch('/graphql', { method: 'POST', body: '...' });
// ...
});
Preload pattern with cache()
components/User.tsx
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.
app/user/[id]/page.tsx
import User, { preload } from '@components/User';
export default async function Page({
params: { id },
}: {
params: Promise<{ id: string }>;
}) {
preload(id); // starting loading the user data now
const condition = await fetchCondition();
return condition ? <User id={id} /> : null;
}
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.
utils/getUser.ts
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.
app/page.tsx
TypeScript
export const revalidate = 60; // revalidate this segment every 60 seconds
Good to know:
- If a page, layout, and fetch request all specify a
revalidatefrequency, the lowest value of the three will be used. - Advanced: You can set
fetchCacheto'only-cache'or'force-cache'to ensure that allfetchrequests opt into caching but the revalidation frequency might still be lowered by individualfetchrequests. SeefetchCachefor more information.