Skip to content

Caching and Revalidating

Source URL: https://nextjs.org/docs/app/getting-started/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.

By default, fetch requests are not cached. You can cache individual requests by setting the cache option to 'force-cache'.

export default async function Page() {
const data = await fetch('https://...', { cache: 'force-cache' })
}
export default async function Page() {
const data = await fetch('https://...', { cache: 'force-cache' })
}

Good to know: Although fetch requests are not cached by default, Next.js will pre-render routes that have fetch requests and cache the HTML. If you want to guarantee a route is dynamic, use the connection API.

To revalidate the data returned by a fetch request, you can use the next.revalidate option.

export default async function Page() {
const data = await fetch('https://...', { next: { revalidate: 3600 } })
}
export default async function Page() {
const data = await fetch('https://...', { next: { revalidate: 3600 } })
}

This will revalidate the data after a specified amount of seconds.

You can also tag fetch requests to enable on-demand cache invalidation:

export async function getUserById(id: string) {
const data = await fetch(`https://...`, {
next: {
tags: ['user'],
},
})
}
export async function getUserById(id) {
const data = await fetch(`https://...`, {
next: {
tags: ['user'],
},
})
}

See the fetch API reference to learn more.

cacheTag allows you to tag cached data in Cache Components so it can be revalidated on-demand. Previously, cache tagging was limited to fetch requests, and caching other work required the experimental unstable_cache API.

With Cache Components, you can use the use cache directive to cache any computation, and cacheTag to tag it. This works with database queries, file system operations, and other server-side work.

import { cacheTag } from 'next/cache'
export async function getProducts() {
'use cache'
cacheTag('products')
const products = await db.query('SELECT * FROM products')
return products
}
import { cacheTag } from 'next/cache'
export async function getProducts() {
'use cache'
cacheTag('products')
const products = await db.query('SELECT * FROM products')
return products
}

Once tagged, you can use revalidateTag or updateTag to invalidate the cache entry for products.

Good to know: cacheTag is used with Cache Components and the use cache directive. It expands the caching and revalidation story beyond fetch.

See the cacheTag API reference to learn more.

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, using fetch with next.tags, or the cacheTag function, you may call revalidateTag in a Route Handler or Server Action:

import { revalidateTag } from 'next/cache'
export async function updateUser(id: string) {
// Mutate data
revalidateTag('user', 'max') // Recommended: Uses stale-while-revalidate
}
import { revalidateTag } from 'next/cache'
export async function updateUser(id) {
// Mutate data
revalidateTag('user', 'max') // Recommended: Uses stale-while-revalidate
}

You can reuse the same tag in multiple functions to revalidate them all at once.

See the revalidateTag API reference to learn more.

updateTag is specifically designed for Server Actions to immediately expire cached data for read-your-own-writes scenarios. Unlike revalidateTag, it can only be used within Server Actions and immediately expires the cache entry.

import { updateTag } from 'next/cache'
import { redirect } from 'next/navigation'
export async function createPost(formData: FormData) {
// Create post in database
const post = await db.post.create({
data: {
title: formData.get('title'),
content: formData.get('content'),
},
})
// Immediately expire cache so the new post is visible
updateTag('posts')
updateTag(`post-${post.id}`)
redirect(`/posts/${post.id}`)
}
import { updateTag } from 'next/cache'
import { redirect } from 'next/navigation'
export async function createPost(formData) {
// Create post in database
const post = await db.post.create({
data: {
title: formData.get('title'),
content: formData.get('content'),
},
})
// Immediately expire cache so the new post is visible
updateTag('posts')
updateTag(`post-${post.id}`)
redirect(`/posts/${post.id}`)
}

The key differences between revalidateTag and updateTag:

  • updateTag: Only in Server Actions, immediately expires cache, for read-your-own-writes
  • revalidateTag: In Server Actions and Route Handlers, supports stale-while-revalidate with profile="max"

See the updateTag API reference to learn more.

revalidatePath is used to revalidate a route and following an event. To use it, call it in a Route Handler or Server Action:

import { revalidatePath } from 'next/cache'
export async function updateUser(id: string) {
// Mutate data
revalidatePath('/profile')
import { revalidatePath } from 'next/cache'
export async function updateUser(id) {
// Mutate data
revalidatePath('/profile')

See the revalidatePath API reference to learn more.

Good to know: unstable_cache is an experimental API. We recommend opting into Cache Components and replacing unstable_cache with the use cache directive. See the Cache Components documentation for more details.

unstable_cache allows you to cache the result of database queries and other async functions. To use it, wrap unstable_cache around the function. For example:

import { db } from '@/lib/db'
export async function getUserById(id: string) {
return db
.select()
.from(users)
.where(eq(users.id, id))
.then((res) => res[0])
}
import { db } from '@/lib/db'
export async function getUserById(id) {
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'
export default async function Page({
params,
}: {
params: Promise<{ userId: string }>
}) {
const { userId } = await params
const getCachedUser = unstable_cache(
async () => {
return getUserById(userId)
},
[userId] // add the user ID to the cache key
)
}
import { unstable_cache } from 'next/cache'
import { getUserById } from '@/app/lib/data'
export default async function Page({ params }) {
const { userId } = await params
const getCachedUser = unstable_cache(
async () => {
return getUserById(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.
const getCachedUser = unstable_cache(
async () => {
return getUserById(userId)
},
[userId],
{
tags: ['user'],
revalidate: 3600,
}
)
const getCachedUser = unstable_cache(
async () => {
return getUserById(userId)
},
[userId],
{
tags: ['user'],
revalidate: 3600,
}
)

See the unstable_cache API reference to learn more.

Learn more about the features mentioned in this page by reading the API Reference.

  • fetch
    • API reference for the extended fetch function.
  • cacheTag
    • Learn how to use the cacheTag function to manage cache invalidation in your Next.js application.
  • revalidateTag
    • API Reference for the revalidateTag function.
  • updateTag
    • API Reference for the updateTag function.
  • revalidatePath
    • API Reference for the revalidatePath function.
  • unstable_cache
    • API Reference for the unstable_cache function.