Caching and revalidating data is also made very straightforward in Next.js 13. You can configure the caching and revalidating behavior on a per-page basis by utilizing a route segment.
Route Segment Config
The Route Segment options allows you to configure the behavior of a Page (opens in a new tab), Layout (opens in a new tab), or Route Handler (opens in a new tab) by directly exporting the following variables:
The two main options we are focusing on are dynamic
and revalidate
.
With these options, you can specify how a page should be rendered:
dynamic
force-static
: This option is similar to usinggetStaticProps
in thepages
directory. It generates a static version of the page at build time or at runtime, which means the page content remains the same until the next build or the next revalidation. This is suitable for pages with data that doesn't frequently change.force-dynamic
: This option is similar to usinggetServerSideProps
in thepages
directory. It enables dynamic rendering of the page on each request, allowing you to fetch and manipulate data before rendering. This is suitable for pages with data that does frequently change.
revalidate
This option is similar to using getStaticProps
in the pages
directory. It generates a static version of the page at build time or at runtime, which means the page content remains the same until the next build or the next revalidation. This is suitable for pages with data that doesn't frequently change.
With these options, you can specify how a page should be rendered: either static
using (just like pages
(getStaticProps) or dynamic
(getServerSideProps) or static with revalidation
Incremental Static Regeneration (ISR) (opens in a new tab)
Examples
We will provide a brief overview to demonstrate caching, which is the most commonly used approach and covers the majority of basic caching use cases.
Static data
To make our page static with the data inside it, we simply need to add the dynamic
route segment and set the value to force-static
. This generates a static version of the page at build time.
export const dynamic = "force-static";
const data = [
{
title: "Title 1",
body: "Lorem ipsum dolor sit amet."
},
{
title: "Title 2",
body: "Consectetur adipiscing elit, sed do eiusmod tempor incididunt."
},
{
title: "Title 3",
body: "Ut labore et dolore magna aliqua."
},
{
title: "Title 4",
body: "Sed ut perspiciatis unde omnis iste natus error."
},
];
async function getData() {
"use server"
return data
}
export default async function Page() {
const data = await getData()
return (
<div className="container mx-auto">
<div className="grid grid-cols-2 gap-4">
{data.map((item, index) => (
<div
key={index}
className="bg-white p-4 shadow rounded-lg"
>
<h2 className="text-lg font-bold mb-2">{item.title}</h2>
<p className="text-gray-700">{item.body}</p>
</div>
))}
</div>
</div>
);
}
dynamic
To prevent data from being cached, we can add a dynamic
route segment with a value of force-dynamic
. This ensures that each page will be dynamic rendered and receive fresh data.
let's edit our getData()
function to better demonstrate this example:
export const dynamic = "force-dynamic"
const data = [
{
title: "Title 1",
body: "Lorem ipsum dolor sit amet."
},
{
title: "Title 2",
body: "Consectetur adipiscing elit, sed do eiusmod tempor incididunt."
},
{
title: "Title 3",
body: "Ut labore et dolore magna aliqua."
},
{
title: "Title 4",
body: "Sed ut perspiciatis unde omnis iste natus error."
},
];
export async function getData(random?: boolean) {
// shuffle the array on each request
if (random) return shuffle(data)
else return data;
}
function shuffle<T>(array: T[]): T[] {
const shuffledArray = [...array];
for (let i = shuffledArray.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[shuffledArray[i], shuffledArray[j]] = [shuffledArray[j], shuffledArray[i]];
}
return shuffledArray;
}
export default async function Page() {
const data = await getData(true)
return (
<div className="container mx-auto">
<div className="grid grid-cols-2 gap-4">
{data.map((item, index) => (
<div
key={index}
className="bg-white p-4 shadow rounded-lg"
>
<h2 className="text-lg font-bold mb-2">{item.title}</h2>
<p className="text-gray-700">{item.body}</p>
</div>
))}
</div>
</div>
);
}
revalidation
We can add revalidate
route segment to revalidate the data every x seconds
export const dynamic = "force-dynamic"
// this will update the cached data every 10 seconds
export const revalidate = 10
Next.js docs
I recommend reading the Next.js documentation (opens in a new tab) to learn more about route segments. Other options can be handy as well.
This is from the Next.js docs, explaining both options we mentioned earlier in detail.
dynamic
'auto'
(default): The default option to cache as much as possible without preventing any components from opting into dynamic behavior.'force-dynamic'
: Force dynamic rendering and dynamic data fetching of a layout or page by disabling all caching offetch
requests and always revalidating. This option is equivalent to:getServerSideProps()
in thepages
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'
'error'
: Force static rendering and static data fetching of a layout or page by causing an error if any components use dynamic functions (opens in a new tab) or dynamic fetches (opens in a new tab). This option is equivalent to:getStaticProps()
in thepages
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
.
'force-static'
: Force static rendering and static data fetching of a layout or page by forcing[cookies()](https://nextjs.org/docs/app/api-reference/functions/cookies)
,[headers()](https://nextjs.org/docs/app/api-reference/functions/headers)
and[useSearchParams()](https://nextjs.org/docs/app/api-reference/functions/use-search-params)
to return empty values.
revalidate
false
: (default) The default heuristic to cache anyfetch
requests that set theircache
option to'force-cache'
or are discovered before a dynamic function (opens in a new tab) is used. Semantically equivalent torevalidate: Infinity
which effectively means the resource should be cached indefinitely. It is still possible for individualfetch
requests to usecache: 'no-store'
orrevalidate: 0
to avoid being cached and make the route dynamically rendered. Or setrevalidate
to a positive number lower than the route default to increase the revalidation frequency of a route.0
: Ensure a layout or page is always dynamically rendered (opens in a new tab) even if no dynamic functions or dynamic data fetches are discovered. This option changes the default offetch
requests that do not set acache
option to'no-store'
but leavesfetch
requests that opt into'force-cache'
or use a positiverevalidate
as is.number
: (in seconds) Set the default revalidation frequency of a layout or page ton
seconds.