Skip to content
Now accepting new projects — limited slots available. Get started →
Architecture · Updated Jul 31, 2026

What is On-Demand Revalidation?

On-demand revalidation is a cache invalidation strategy that regenerates static pages when triggered by an explicit event.

What is On-Demand Revalidation?

On-demand revalidation is a cache invalidation strategy where statically generated pages are regenerated only when an explicit signal—typically an API call or webhook—tells the server that content has changed. Unlike time-based Incremental Static Regeneration (ISR), which rebuilds pages on a fixed interval (e.g., every 60 seconds), on-demand revalidation fires precisely when the underlying data updates. Next.js introduced this pattern in v12.1 (February 2022) via the res.revalidate() API, and it became the default mental model in the App Router with revalidatePath() and revalidateTag() starting in Next.js 13.4 (May 2023). The result is pages that stay static—serving at CDN speed—but never show stale content for longer than it takes the webhook to fire and the rebuild to complete. We use it on nearly every headless CMS project we ship, especially when editors expect publish-then-see-it-live in under two seconds.

How it works

The flow has three moving parts: a data source, a trigger mechanism, and the revalidation endpoint.

  1. Data source changes. An editor publishes a blog post in a CMS like Sanity, Contentful, or Payload.
  2. Webhook fires. The CMS sends an HTTP POST to a route in your app (e.g., /api/revalidate) with a payload describing what changed.
  3. Server regenerates. Your route handler calls the framework's revalidation API, which purges the cached page and rebuilds it on the next request—or immediately, depending on configuration.

In the Next.js App Router (v13.4+), the code looks like this:

// app/api/revalidate/route.ts
import { revalidateTag } from 'next/cache';
import { NextRequest, NextResponse } from 'next/server';

export async function POST(req: NextRequest) {
  const secret = req.headers.get('x-revalidation-secret');
  if (secret !== process.env.REVALIDATION_SECRET) {
    return NextResponse.json({ message: 'Invalid secret' }, { status: 401 });
  }

  const { tag } = await req.json();
  revalidateTag(tag);
  return NextResponse.json({ revalidated: true, tag });
}

On the data-fetching side, you tag your fetch calls:

const res = await fetch('https://cms.example.com/api/posts', {
  next: { tags: ['posts'] },
});

When the webhook hits /api/revalidate with { "tag": "posts" }, every page that used the posts tag gets purged and rebuilt. Vercel, Netlify, and Cloudflare all support this pattern at the CDN edge, so the stale page is replaced globally, not just on a single server.

When to use it

On-demand revalidation is the right choice when content changes are event-driven and infrequent-to-moderate (think blog posts, product pages, marketing landing pages). It gives you static performance with dynamic freshness.

Use it when:

  • You have a headless CMS with webhook support (Sanity, Contentful, Strapi, Payload, etc.)
  • Content updates happen on a human schedule (minutes to hours apart, not seconds)
  • Stale content is a business problem—pricing pages, legal disclaimers, inventory counts
  • You want CDN-level TTFB (often sub-50ms) without serving outdated data

Don't use it when:

  • Data changes every few seconds (stock tickers, live scores)—use server rendering or streaming instead
  • You have thousands of interdependent pages that all invalidate at once—this can cause a thundering herd of rebuilds
  • Your hosting provider doesn't support on-demand purging at the edge (self-hosted Node without a CDN layer)

On-Demand Revalidation vs alternatives

Strategy Trigger Freshness TTFB Complexity
On-Demand Revalidation Webhook / API call Near-instant after publish ~20-80ms (CDN) Medium
Time-Based ISR Fixed interval (e.g., 60s) Up to revalidate seconds stale ~20-80ms (CDN) Low
Full Static (SSG) Build-time only Stale until next deploy ~20-80ms (CDN) Low
Server-Side Rendering (SSR) Every request Always fresh ~150-500ms+ Low-Medium
Stale-While-Revalidate (SWR client) Client fetch Stale then fresh on revalidate Varies Medium

Time-based ISR is simpler but wasteful—it rebuilds pages even when nothing changed and can still serve stale content within the window. SSR is always fresh but slower. On-demand revalidation sits in the sweet spot: you get static speed and only pay the rebuild cost when data actually changes. We've shipped this on 50+ projects and it's our default recommendation for any site backed by a CMS.

Real-world example

We built a 1,200-page e-commerce catalog on Next.js 14 with Sanity as the CMS, deployed to Vercel. Product pages were statically generated at build time with revalidateTag. When a merchandiser updated a price or toggled a product's availability in Sanity, a GROQ-powered webhook fired to our /api/revalidate route with the product's slug as the tag. The affected page was purged and rebuilt within 1.3 seconds on average. The site maintained a median TTFB of 38ms across all product pages (measured via CrUX), and editors stopped asking "why doesn't my change show up?"—a question that had plagued the old 60-second ISR setup.

Frequently asked questions about On-Demand Revalidation

Is on-demand revalidation the same as Incremental Static Regeneration (ISR)?
Not exactly. ISR is the broader concept of regenerating static pages after the initial build. Time-based ISR uses a `revalidate` interval (e.g., every 60 seconds) to trigger rebuilds regardless of whether data changed. On-demand revalidation is a specific ISR strategy where the rebuild is triggered by an explicit event—usually a webhook or API call. Think of time-based ISR as polling and on-demand revalidation as event-driven push. Next.js supports both, and you can mix them: use a long time-based fallback (say, 3600 seconds) alongside on-demand triggers for belt-and-suspenders freshness.
When did on-demand revalidation become standard in Next.js?
Next.js introduced on-demand revalidation in v12.1, released in February 2022, via `res.revalidate()` in API routes. It was a Pages Router feature. When the App Router stabilized in Next.js 13.4 (May 2023), the pattern shifted to `revalidatePath()` and `revalidateTag()`, which are more ergonomic because they work with the built-in fetch cache and don't require manually tracking page paths. By Next.js 14 (October 2023), tag-based revalidation became the recommended approach in the official docs. As of April 2026, it's the de facto standard for any statically optimized Next.js site backed by a CMS.
What's the alternative to on-demand revalidation?
The most common alternatives are time-based ISR and full server-side rendering. Time-based ISR is simpler to set up—just add `revalidate: 60` to your fetch options—but it can serve stale content for up to that interval and wastes compute rebuilding pages when nothing changed. SSR (`force-dynamic` or `no-store` in the App Router) guarantees freshness on every request but sacrifices CDN caching, so TTFB jumps from ~30-80ms to 150-500ms+. For client-heavy apps, you could also use SWR or React Query to fetch fresh data on the client while serving a static shell. Our preferred stack is on-demand revalidation with a long time-based fallback as a safety net.
How do you secure an on-demand revalidation endpoint?
Always protect it with a shared secret. Generate a random token, store it in your environment variables, and configure your CMS webhook to send it as a header (e.g., `x-revalidation-secret`). In your route handler, compare the incoming header against `process.env.REVALIDATION_SECRET` and return a 401 if it doesn't match. Some teams also restrict the endpoint by IP allowlist if their CMS publishes from known IPs. We also recommend rate-limiting the endpoint—a misconfigured webhook can fire hundreds of times during a bulk content import and cause a rebuild storm. A simple in-memory counter or a queue (like Inngest or QStash) can throttle bursts.
Get in touch

Let's build
something together.

Whether it's a migration, a new build, or an SEO challenge — the Social Animal team would love to hear from you.

Get in touch →