Why on-demand
Time-based ISR means users might see stale data for the whole revalidate window. On-demand revalidation lets you invalidate the cache the instant a mutation lands — so editors who change content see the new version immediately.
Two functions, two scopes
| Function | Invalidates |
|---|---|
revalidatePath(path, type?) | A specific path. type can be 'page' (just the leaf) or 'layout' (everything under). |
revalidateTag(tag) | Every fetch tagged with tag via fetch(url, { next: { tags } }). |
Where you can call them
Server Actions and Route Handlers only. v15 made this strict; calling them during render throws. The reason: invalidation is a side effect that belongs to mutations, not to pure rendering.
Model invalidation from the data outward. Updating one post can affect its detail view, the listing, and an author page. Stable tags such as post:<id> plus a collection tag often express that dependency more safely than a growing list of paths. One global tag makes implementation easy but destroys most of the cache on every change. Extremely narrow ID tags can leave aggregates stale. The useful middle is a small vocabulary aligned with actual data relationships.
Render the same record in three locations and compare path and tag invalidation after create, update, and delete. Invalidation must happen only after a successful write, and a render-time call should remain a failing regression test.