Implementing Incremental Static Regeneration (ISR) and On-Demand Revalidation

Static Site Generation (SSG) delivers blazing-fast performance by pre-rendering pages at build time. However, in large-scale applications with thousands of dynamic pages—such as e-commerce catalogs, news portals, or content management systems—rebuilding the entire site every time a piece of content changes is impractical.

Next.js solves this challenge through Incremental Static Regeneration (ISR), allowing developers to update static pages in the background without a full site rebuild. Combined with On-Demand Revalidation, you can purge and regenerate pages instantly the moment underlying data changes.

This comprehensive guide explores the mechanics of ISR, time-based revalidation, and on-demand cache purging using Next.js Server Actions and API routes.

What is Incremental Static Regeneration?

Incremental Static Regeneration bridges the gap between static site generation and server-side rendering. It enables you to create or update static pages incrementally after your application has been built and deployed.

When a user requests a static page whose revalidation window has expired, Next.js serves the cached, stale version immediately to ensure low latency while triggering a background regeneration of the page.

TypeScript
Configuring time-based ISR revalidation using fetch options in a Server Component.
async function getArticles() {
  const res = await fetch('https://api.example.com/articles', {
    next: { revalidate: 60 } // Revalidate cache at most once every 60 seconds
  });
  
  if (!res.ok) {
    throw new Error('Failed to fetch articles');
  }
  
  return res.json();
}

export default async function ArticlesPage() {
  const articles = await getArticles();

  return (
    <main className="container mx-auto px-4 py-8">
      <h1 className="text-3xl font-bold mb-6">Latest Articles</h1>
      <div className="grid gap-4">
        {articles.map((article: any) => (
          <article key={article.id} className="p-4 bg-white rounded-lg shadow">
            <h2 className="text-xl font-semibold">{article.title}</h2>
          </article>
        ))}
      </div>
    </main>
  );
}

Purging Cache Instantly with On-Demand Revalidation

While time-based revalidation is effective for predictable data updates, certain scenarios require immediate cache purging—such as a CMS publishing a breaking news story, an administrator modifying a product price, or a user updating their profile.

Next.js provides two powerful utilities for clearing cache on-demand: revalidatePath (to purge a specific route) and revalidateTag (to purge data tied to specific cache tags).

TypeScript
Using revalidatePath inside a Next.js Server Action to purge cache instantly.
'use server';

import { revalidatePath, revalidateTag } from 'next/cache';
import db from '@/lib/db';

export async function updateArticle(id: string, title: string) {
  // Update record in the database
  await db.article.update({
    where: { id },
    data: { title },
  });

  // Instantly purge cache for the specific article route
  revalidatePath(`/articles/${id}`);
  
  // Alternatively, purge cache across all components sharing this tag
  revalidateTag('articles-list');
}

Triggering Revalidation via Headless CMS Webhooks

For production applications backed by headless Content Management Systems (CMS) like Strapi, Sanity, or Contentful, you can configure webhook endpoints to notify your Next.js application whenever content is published or edited.

TypeScript
Implementing a Next.js API Route handler to process CMS revalidation webhooks securely.
import { NextRequest, NextResponse } from 'next/server';
import { revalidateTag } from 'next/cache';

export async function POST(request: NextRequest) {
  try {
    const body = await request.json();
    const secret = request.headers.get('x-webhook-secret');

    // Verify secret token to prevent unauthorized cache purging
    if (secret !== process.env.CMS_WEBHOOK_SECRET) {
      return NextResponse.json({ message: 'Invalid secret token' }, { status: 401 });
    }

    const tag = body.tag || 'default';
    revalidateTag(tag);

    return NextResponse.json({ revalidated: true, now: Date.now() });
  } catch (err) {
    return NextResponse.json({ message: 'Error revalidating' }, { status: 500 });
  }
}

Summary

Incremental Static Regeneration (ISR) and On-Demand Revalidation combine the unmatched performance and reliability of static sites with the dynamic flexibility of server-rendered applications.

By leveraging time-based revalidation for background updates and On-Demand Revalidation via Server Actions or webhooks for instant content syncing, you can maintain optimal web performance across large-scale Next.js applications.