Source: Finally Master Next.js’s Most Complex Feature - Caching (webdevsimplified.com)
By default, Next.js automatically caches data in the data cache for every fetch
request in server components. The data cache is the last cache Next.js hits before fetching data from APIs or the database. It is also persistent across multiple requests and users.
If there are 100 users requesting the same data, Next.js will fetch it only once, store it in the data cache, and return it from the cache to 100 users.
export default async function Page({ params }) {
const city = params.city
const res = await fetch(`https://api.globetrotter.com/guides/${city}`)
const guideData = await res.json()
return (
<div>
<h1>{guideData.title}</h1>
<p>{guideData.content}</p>
{/* Render the guide data */}
</div>
)
}
For example, the guideData
will only be fetched from the API once and stored in the data cache. All users will get the data from the data cache instead of fetching it from the API.
Revalidation
Data cache is never cleared, even if you redeploy your application. The only way to update the cache is to explicitly tell Next.js to do so using time-based revalidation or on-demand revalidation.
Time-based revalidation
We can tell Next.js to automatically revalidate the data in the data cache by declaring a time period. You can either declare the time as the second parameter (options) in the fetch
function, or declare it as a config option of the page.
Next.js implements time-based revalidation with a pattern called stale-while-revalidate
. Here is how it works:
fetch
the data from the API and store it in the data cache.- Within 1 hour, each
fetch
returns only the data from the data cache. - After 1 hour, the first
fetch
returns the data from the data cache, but it also makes the request with API and updates the data cache with new data. - The next
fetch
returns the new data in the data cache.
// The cache of this fetch will be revalidated after 1 hour
const res = fetch(`https://api.globetrotter.com/guides/${city}`, {
next: { revalidate: 3600 },
})
// all cache of this page will be revalidated after 1 hour
export const revalidate = 3600
export default async function Page({ params }) {
const city = params.city
const res = await fetch(`https://api.globetrotter.com/guides/${city}`)
const guideData = await res.json()
return (
<div>
<h1>{guideData.title}</h1>
<p>{guideData.content}</p>
{/* Render the guide data */}
</div>
)
}
Important
The time period declared in the fetch function has higher priority than the one declared in the page when two methods are used at the same time.
On-demand Revalidation
There are two ways to revalidate the data cache by calling functions instead of waiting for a period of time.
revalidatePath
will clear the cache of allfetch
requests on the path you pass.
import { revalidatePath } from "next/cache"
export async function publishArticle({ city }) {
createArticle(city)
revalidatePath(`/guides/${city}`)
}
revalidateTag
will clear the cache of allfetch
requests that havetags
specified in theirfetch
function.
const res = fetch(`https://api.globetrotter.com/guides/${city}`, {
next: { tags: ["city-guides"] },
})
import { revalidateTag } from "next/cache"
export async function publishArticle({ city }) {
createArticle(city)
revalidateTag("city-guides")
}
Opting Out
If you don’t want Next.js to cache fetch
requests in the data cache, for example, if the fetch
results need to be fresh for every user, you can declare no-store
in your fetch
function to disable the data cache.
const res = fetch(`https://api.globetrotter.com/guides/${city}`, {
cache: "no-store",
})
Another way is to declare force-dynamic
to the dynamic
segment config option of the page, or set 0
to revalidate
. Both declarations will disable the data cache for all fetch
requests on the same page.
export const dynamic = "force-dynamic"
export const revalidate = 0
Caching Non-fetch
Requests
You can use the experimental unstable_cache API of Next.js to cache non-fetch
requests in the data cache.
References