Next.js ISR and On-Demand Revalidation Explained
A practical look at Next.js ISR vs on-demand revalidation, cache tag strategies, webhook integration, and common caching mistakes to avoid.
Next.js's Incremental Static Regeneration pre-renders pages at build time and refreshes them in the background using a stale-while-revalidate model, so users never wait on a slow render but may briefly see outdated content. Time-based ISR (e.g. revalidate: 3600) suits predictable, tolerably-stale content, but it falls short when urgent edits — a price change, an event cancellation — need to appear before the revalidation window expires.
On-demand revalidation addresses that gap: revalidatePath and revalidateTag let you invalidate specific pages or cache tags programmatically, typically triggered by a CMS webhook when content is published. Tagging fetches (e.g. a post tag and a shared list tag) lets a single event refresh both a detail page and its listing. The recommended pattern combines both approaches — time-based revalidation as a safety net in case webhook delivery fails, and tag-based on-demand revalidation as the primary mechanism for intentional updates.
Common pitfalls include using revalidate: 0 (which disables caching entirely instead of enabling on-demand-only behavior via revalidate: false), leaving the revalidation endpoint unsecured without a secret check, revalidating too broadly at the layout level, and failing to monitor webhook or endpoint errors. A key nuance for engineers: calling revalidateTag doesn't guarantee instant freshness — it only triggers regeneration on the next incoming request.