Cache
Categories:
Route Segment Config Options
The Route Segment Config Options allows you configure the behavior of a Page
, Layout
, or Route Handler
by directly exporting the following variables:
// layout.js|page.js
export const dynamic = 'auto'
export const dynamicParams = true
export const revalidate = false
export const fetchCache = 'auto'
export const runtime = 'nodejs'
export const preferredRegion = 'auto'
export function generateStaticParams(...)
dynamic
Change the dynamic behavior of a layout or page to fully static or fully dynamic.
export const dynamic = 'auto'
// 'auto' | 'force-dynamic' | 'error' | 'force-static'
Options | Description |
---|---|
auto (default) |
Cache as much as possible without preventing any components from opting into dynamic behavior |
force-dynamic |
Disabling all caching of fetch requests and always revalidating |
error |
Force static rendering and static data fetching of a layout or page by causing an error |
force-static |
Force static rendering and static data fetching of a layout or page by forcing cookies() , headers() and useSearchParams() to return empty values. |
dynamic = force-dynamic
Equivalent
getServerSideProps()
in the pages directory.- Setting the option of every
fetch()
request in a layout or page to{ cache: 'no-store', next: { revalidate: 0 } }
. - Setting the segment config to export const
fetchCache = 'force-no-store'
dynamic = error
Equivalent
getStaticProps()
in the pages directory.- Setting the option of every
fetch()
request in a layout or page to{ cache: 'force-cache' }
. - Setting the segment config to
fetchCache = 'only-cache'
,dynamicParams = false
. - Note:
dynamic = 'error'
changes the default ofdynamicParams
fromtrue
tofalse
. You can opt back into dynamically rendering pages for dynamic params not generated bygenerateStaticParams
by manually settingdynamicParams = true
.
dynamicParams
Control what happens when a dynamic segment is visited that was not generated with generateStaticParams
.
export const dynamicParams = true // true | false,
Options | Description |
---|---|
true (default) |
Dynamic segments not included in generateStaticParams are generated on demand. |
false |
Dynamic segments not included in generateStaticParams will return a 404. |
Notes
- This option replaces the
fallback: true | false | blocking
option of getStaticPaths in the pages directory. - When
dynamicParams = true
, the segment uses Streaming Server Rendering. - If the
dynamic = 'error'
anddynamic = 'force-static'
are used, it’ll change the default ofdynamicParams
tofalse
.
revalidate
Set the default revalidation time for a layout
or page
This option does NOT override the
revalidate value
set by individualfetch
requests.
export const revalidate = false
// false | 'force-cache' | 0 | number
Options | Description |
---|---|
false (default) |
To cache any fetch requests that set their cache option to 'force-cache' or are discovered before a dynamic function is used. |
0 |
Ensure a layout or page is always dynamically rendered |
number (in seconds) |
Set the default revalidation frequency of a layout or page to n seconds. |
revalidate = false
Equivalent
revalidate: Infinity
It is still possible for individual fetch requests
to use cache: 'no-store'
or revalidate: 0
to avoid being cached and make the route dynamically rendered.
revalidate = 0
- Changes the default of
fetch() requests
cache option to'no-store'
iffetch()
cache option NOT set. fetch() requests
cache options that set to'force-cache'
or use apositive revalidate
will still work as is
Revalidation Frequency
-
The lowest revalidate across each
layout
andpage
of a single route will determine the revalidation frequency of the entire route. This ensures thatchild pages
are revalidated as frequently as theirparent layouts
. -
Individual fetch requests
can set a lower revalidate than the route’s default revalidate toincrease the revalidation frequency
of the entire route.
fetchCache
fetchCache
allows you to override the default cache option of all fetch requests
in a layout or page.
// layout.js
export const fetchCache = 'auto'
// 'auto' | 'default-cache' | 'only-cache'
// 'force-cache' | 'force-no-store' | 'default-no-store' | 'only-no-store'
Options | Description |
---|---|
auto (default) |
Cache fetch requests before dynamic functions with the cache option they provide and NOT cache fetch requests after dynamic functions. |
default-cache |
Allow any cache option to be passed to fetch but if NO option is provided then set the cache option to 'force-cache' |
only-cache |
Ensure all fetch requests opt into caching by changing the default to cache: 'force-cache' if no option is provided. Causing an error if any fetch requests use cache: 'no-store' . |
force-cache |
Ensure all fetch requests opt into caching by setting the cache option of all fetch requests to 'force-cache' . |
force-no-store |
Allow any cache option to be passed to fetch but if NO option is provided then set the cache option to 'no-store' . This means that even fetch requests before dynamic functions are considered dynamic. |
default-no-store |
Ensure all fetch requests opt out of caching by changing the default to cache: 'no-store' if no option is provided. Causing an error if any fetch requests use cache: 'force-cache' |
only-no-store |
Ensure all fetch requests opt out of caching by setting the cache option of all fetch requests to 'no-store' . This forces all fetch requests to be re-fetched every request even if they provide a 'force-cache' option. |
Cross-route segment behavior
page1.js | page2.js | Winner |
---|---|---|
only-cache |
force-cache |
force-cache |
only-no-store |
force-no-store |
force-no-store |
The force option changes the behavior across the route so a single segment with 'force-*'
would prevent any errors caused by 'only-*'
.
page1.js | page2.js | Not allowed |
---|---|---|
only-cache |
only-no-store |
X |
force-cache |
force-no-store |
X |
default-no-store |
auto or *-cache |
X |
The intention of the 'only-*'
and force-*'
options is to guarantee the whole route is either fully static or fully dynamic.
runtime
// layout.js
export const runtime = 'nodejs'
// 'experimental-edge' | 'nodejs'
preferredRegion
If a preferredRegion is NOT specified, it’ll inherit the option of the nearest parent layout.
The root layout defaults to auto
.
// layout.js
export const preferredRegion = 'auto'
// 'auto' | 'home' | 'edge' | 'string'
Options | Description |
---|---|
auto (default) |
Either the specified home region on your platform or the Edge if no waterfall requests are detected. |
home |
The specified home region on your platform. |
edge |
The Edge Network , if one is available on your platform. |
generateStaticParams
To define the list of route segment parameters that will be statically generated at build time
instead of on-demand at request time
.
Segment-level Caching
Segment-level caching allows you to cache and revalidate data used in route segments
.
Route Segment Cache Options
// app/page.tsx
export const revalidate = 60; // revalidate this page every 60 seconds
Fetch function specify a revalidate option
// app/page.tsx
// revalidate this page every 10 seconds, since the getData's fetch
// request has `revalidate: 10`.
async function getData() {
const res = await fetch('https://...', { next: { revalidate: 10 } });
return res.json();
}
export default async function Page() {
const data = await getData();
// ...
}
Different revalidate setting priority
If a page
, layout
, and fetch request
all specify a revalidation frequency
then the lowest value of the three will be used.
export const revalidate = 30;
async function getData() {
const res = await fetch('https://...', { next: { revalidate: 10 } });
return res.json();
}
export default async function Page() {
const data = await getData();
// ...
}
Since the fetch request has the shortest revalidation time, this page will use its value and be revalidated every 10 seconds.
Per-request Caching
React exposes a new function, cache()
, that memoizes the result of a wrapped function
// utils/getUser.ts
import { cache } from 'react';
export const getUser = cache(async (id: string) => {
const user = await db.user.findUnique({ id });
return user;
});
// app/user/[id]/layout.tsx
import { getUser } from '@utils/getUser';
export default async function UserLayout({ params: { id } }) {
const user = await getUser(id);
// ...
}
// app/user/[id]/page.tsx
import { getUser } from '@utils/getUser';
export default async function UserLayout({
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.
GraphQL and cache()
Only GET requests
are cache on the fetch()
function. But you can use cache()
to cache the POST requests
.
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()
The preload()
function can have any name. It’s a pattern, NOT an API.
// 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);
// ...
}
// app/user/[id]/page.tsx
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;
}
Using On-Demand Revalidation
https://<your-site.com>/api/revalidate?secret=<token>
Add the secret as an Environment Variable to your application.
MY_SECRET_TOKEN=<token>
Create the revalidation API Route:
// pages/api/revalidate.js
export default async function handler(req, res) {
// Check for secret to confirm this is a valid request
if (req.query.secret !== process.env.MY_SECRET_TOKEN) {
return res.status(401).json({ message: 'Invalid token' });
}
try {
// This should be the actual path not a rewritten path
// e.g. for "/blog/[slug]" this should be "/blog/post-1"
await res.revalidate('/path-to-revalidate');
return res.json({ revalidated: true });
} catch (err) {
// If there was an error, Next.js will continue
// to show the last successfully generated page
return res.status(500).send('Error revalidating');
}
}
Testing On-Demand Revalidation During Development
next build
next start