Skip to content

Revalidation and Cache Invalidation

Once data is in the Data Cache you invalidate it two ways — time-based (let it go stale after N seconds) or on-demand (revalidateTag / revalidatePath after a mutation) — and both also refresh the Full Route Cache for affected routes.

Give a cached fetch a lifetime with next: { revalidate: N }, or set it for a whole route segment with export const revalidate. After the window passes, the next request triggers a background refresh.

// Per fetch: this data is at most 60 seconds stale
await fetch('https://api.example.com/posts', { next: { revalidate: 60 } })
// app/blog/page.tsx — revalidate the entire segment every hour
export const revalidate = 3600

For data that changes on an event, not a clock, tag the fetch, then call revalidateTag after the mutation. Every fetch carrying that tag is dropped from the Data Cache.

lib/posts.ts
export async function getPosts() {
const res = await fetch('https://api.example.com/posts', {
next: { tags: ['posts'] },
})
return res.json()
}
app/actions.ts
'use server'
import { revalidateTag } from 'next/cache'
export async function createPost(formData: FormData) {
await fetch('https://api.example.com/posts', {
method: 'POST',
body: JSON.stringify({ title: formData.get('title') }),
})
// Invalidate every fetch tagged 'posts'
revalidateTag('posts')
}

Both run inside a Server Action or Route Handler. revalidateTag targets data by tag, wherever it is fetched. revalidatePath targets a route and clears everything cached for it — reach for it when you do not know the tags.

'use server'
import { revalidatePath } from 'next/cache'
export async function updateProfile() {
// Re-render and refetch everything for this exact route
revalidatePath('/profile')
}

Revalidation touches two of the four layers. It drops the matching entries from the Data Cache, and because a route’s rendered output depends on that data, it also marks the affected Full Route Cache entries stale. The next request re-runs the render with fresh data and repopulates both. Request Memoization and the client Router Cache are untouched — the Router Cache refreshes on its own after a Server Action.

flowchart LR
  A["Server Action: mutate"] --> B["revalidateTag('posts')"]
  B --> C["Data Cache: drop tagged entries"]
  C --> D["Full Route Cache: mark routes stale"]
  D --> E["Next request re-renders with fresh data"]
A mutation invalidating the Data and Route caches
What are the two ways to do time-based revalidation?
Where may you call revalidateTag?
How does revalidatePath differ from revalidateTag?
What must a fetch have before revalidateTag can invalidate it?