Revalidation and Cache Invalidation
The idea in one sentence
Section titled “The idea in one sentence”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.
Time-based revalidation
Section titled “Time-based revalidation”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 staleawait fetch('https://api.example.com/posts', { next: { revalidate: 60 } })// app/blog/page.tsx — revalidate the entire segment every hourexport const revalidate = 3600On-demand revalidation with tags
Section titled “On-demand revalidation with tags”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.
export async function getPosts() { const res = await fetch('https://api.example.com/posts', { next: { tags: ['posts'] }, }) return res.json()}'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')}revalidatePath vs. revalidateTag
Section titled “revalidatePath vs. revalidateTag”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')}How it maps onto the two server caches
Section titled “How it maps onto the two server caches”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"]