Caching and Revalidating
Caching is a technique for storing the result of data fetching and other computations so that future requests for the same data can be served faster, without doing the work again. While revalidation allows you to update cache entries without having to rebuild your entire application.
Next.js provides a few APIs to handle caching and revalidation. This guide will walk you through when and how to use them.
fetch
By default,fetch requests are not cached. You can cache individual requests by setting thecache option to'force-cache'.
exportdefaultasyncfunctionPage() {constdata=awaitfetch('https://...', { cache:'force-cache' })}Good to know: Although
fetchrequests are not cached by default, Next.js willpre-render routes that havefetchrequests and cache the HTML. If you want to guarantee a route isdynamic, use theconnectionAPI.
To revalidate the data returned by afetch request, you can use thenext.revalidate option.
exportdefaultasyncfunctionPage() {constdata=awaitfetch('https://...', { next: { revalidate:3600 } })}This will revalidate the data after a specified amount of seconds.
You can also tagfetch requests to enable on-demand cache invalidation:
exportasyncfunctiongetUserById(id:string) {constdata=awaitfetch(`https://...`, { next: { tags: ['user'], }, })}See thefetch API reference to learn more.
cacheTag
cacheTag allows you to tag cached data inCache Components so it can be revalidated on-demand. Previously, cache tagging was limited tofetch requests, and caching other work required the experimentalunstable_cache API.
With Cache Components, you can use theuse cache directive to cache any computation, andcacheTag to tag it. This works with database queries, file system operations, and other server-side work.
import { cacheTag }from'next/cache'exportasyncfunctiongetProducts() {'use cache'cacheTag('products')constproducts=awaitdb.query('SELECT * FROM products')return products}Once tagged, you can userevalidateTag orupdateTag to invalidate the cache entry for products.
Good to know:
cacheTagis used withCache Components and theuse cachedirective. It expands the caching and revalidation story beyondfetch.
See thecacheTag API reference to learn more.
revalidateTag
revalidateTag is used to revalidate cache entries based on a tag and following an event. The function now supports two behaviors:
- With
profile="max": Uses stale-while-revalidate semantics, serving stale content while fetching fresh content in the background - Without the second argument: Legacy behavior that immediately expires the cache (deprecated)
After tagging your cached data, usingfetch withnext.tags, or thecacheTag function, you may callrevalidateTag in aRoute Handler or Server Action:
import { revalidateTag }from'next/cache'exportasyncfunctionupdateUser(id:string) {// Mutate datarevalidateTag('user','max')// Recommended: Uses stale-while-revalidate}You can reuse the same tag in multiple functions to revalidate them all at once.
See therevalidateTag API reference to learn more.
updateTag
updateTag is specifically designed for Server Actions to immediately expire cached data for read-your-own-writes scenarios. UnlikerevalidateTag, it can only be used within Server Actions and immediately expires the cache entry.
import { updateTag }from'next/cache'import { redirect }from'next/navigation'exportasyncfunctioncreatePost(formData:FormData) {// Create post in databaseconstpost=awaitdb.post.create({ data: { title:formData.get('title'), content:formData.get('content'), }, })// Immediately expire cache so the new post is visibleupdateTag('posts')updateTag(`post-${post.id}`)redirect(`/posts/${post.id}`)}The key differences betweenrevalidateTag andupdateTag:
updateTag: Only in Server Actions, immediately expires cache, for read-your-own-writesrevalidateTag: In Server Actions and Route Handlers, supports stale-while-revalidate withprofile="max"
See theupdateTag API reference to learn more.
revalidatePath
revalidatePath is used to revalidate a route and following an event. To use it, call it in aRoute Handler or Server Action:
import { revalidatePath }from'next/cache'exportasyncfunctionupdateUser(id:string) {// Mutate datarevalidatePath('/profile')See therevalidatePath API reference to learn more.
unstable_cache
Good to know:
unstable_cacheis an experimental API. We recommend opting intoCache Components and replacingunstable_cachewith theuse cachedirective. See theCache Components documentation for more details.
unstable_cache allows you to cache the result of database queries and other async functions. To use it, wrapunstable_cache around the function. For example:
import { db }from'@/lib/db'exportasyncfunctiongetUserById(id:string) {return db.select().from(users).where(eq(users.id, id)).then((res)=> res[0])}import { unstable_cache }from'next/cache'import { getUserById }from'@/app/lib/data'exportdefaultasyncfunctionPage({ params,}: { params:Promise<{ userId:string }>}) {const {userId }=await paramsconstgetCachedUser=unstable_cache(async ()=> {returngetUserById(userId) }, [userId]// add the user ID to the cache key )}The function accepts a third optional object to define how the cache should be revalidated. It accepts:
tags: an array of tags used by Next.js to revalidate the cache.revalidate: the number of seconds after cache should be revalidated.
constgetCachedUser=unstable_cache(async ()=> {returngetUserById(userId) }, [userId], { tags: ['user'], revalidate:3600, })See theunstable_cache API reference to learn more.
API Reference
fetch
cacheTag
revalidateTag
updateTag
revalidatePath
unstable_cache
Was this helpful?