Incremental Static Regeneration (ISR)

Level 8 — Rendering Strategies & Cache A hybrid rendering strategy that gives you the speed of SSG (Static HTML) with the flexibility to update that HTML periodically in the background without needing to rebuild the entire application.


1. Prerequisites


2. Term Category

Rendering Strategy (Incremental Static Regeneration): Incremental Static Regeneration (ISR) revalidates static HTML pages in the background on demand or time intervals without rebuilding the entire site.


3. Explanation

Environment Context

  • Server (Build-Time & Request-Time)

(1) Design Motivation — "Why did we design this?"

SSG is incredibly fast, but if your site has 100,000 product pages, running npm run build to generate all 100,000 HTML files might take 2 hours. If a price changes on one product, you have to wait 2 hours to deploy the fix. Incremental Static Regeneration (ISR) solves this by allowing you to create or update static pages after the build has finished, on a page-by-page basis.

(2) How it works (The Stale-While-Revalidate Pattern)

In the App Router, ISR is implemented by combining Static Rendering with the next.revalidate fetch option (or exporting const revalidate = 60).

// app/products/page.tsx
export const revalidate = 60; // Enable ISR with a 60-second timer!

export default async function ProductsPage() {
  const products = await db.product.findMany();
  return <ul>{products.map(p => <li>{p.name} - ${p.price}</li>)}</ul>;
}

The Flow:

  1. Build Time: Next.js generates the static HTML for /products and deploys it.
  2. 0s - 60s: 1,000 users visit. They get the lightning-fast static HTML.
  3. 61s: The cache expires. User #1,001 visits. They still get the old static HTML! But Next.js instantly triggers a background process to re-run the React component and generate a new HTML file.
  4. 65s: The new HTML file replaces the old one. User #1,002 gets the fresh data.

(3) Generating pages on-the-fly

ISR isn't just about updating existing pages; it can generate new pages! If you have a dynamic route app/post/[slug]/page.tsx, and a user visits /post/brand-new-post (which wasn't generated at build time), Next.js will generate the HTML on-the-fly for that first user, save it to disk, and serve it statically to every user after them!


4. Common Mistakes & Pitfalls

Mistake 1: Expecting ISR to update instantly

The mistake: A marketing manager updates a typo on the homepage. They refresh the page and don't see the fix. They complain the site is broken.

Why it's wrong: ISR uses the "Stale-While-Revalidate" pattern. The very first visitor after the timer expires always receives the old, stale HTML. Their visit is simply the trigger that tells the server to build the new version in the background. You have to refresh a second time to see the new content. Golden Rule: If instant updates are absolutely critical (like publishing a breaking news story), do not rely on time-based ISR. Use On-Demand Revalidation (revalidatePath) to instantly purge the cache.


Mistake 2: Confusing Incremental Static Regeneration (ISR) with Traditional Static Site Generation (SSG)

The mistake: Expecting ISR pages to require a full CI/CD deployment build to update content.

Why it's wrong: ISR allows updating static pre-rendered HTML pages in the background after deployment without triggering a full site re-build.

Incorrect:

/* Triggering full 20-minute CI/CD site rebuild to update 1 product price */

Fix:

/* Use ISR (revalidate: 60) or on-demand revalidateTag('products') for background updates */

Mistake 3: Setting Extremely Short ISR Revalidate Timers (revalidate: 1) for High-Traffic Sites

The mistake: Setting export const revalidate = 1 on pages receiving 10,000 requests per second.

Why it's wrong: Extremely short timers force Next.js to trigger background revalidation builds continuously, negating static caching benefits and increasing server load. Balance timers or use event-based tags.

Incorrect:

export const revalidate = 1; // ❌ Revalidates every second, inflating server load!

Fix:

export const revalidate = 300; // 5-minute timer + revalidateTag() for instant updates

5. Practice Exercises

Exercise 1: Configuring Time-Based ISR in Route Segments

Scenario: Configure a news index route segment to revalidate cached static HTML every 60 seconds.

Requirements:

  1. Export export const revalidate = 60 in page.tsx.
Answer

Implementation

// app/news/page.tsx
export const revalidate = 60; // Revalidate every 60 seconds

export default async function NewsPage() {
  const news = await fetch("https://api.example.com/latest-news").then((r) => r.json());

  return (
    <main className="p-6">
      <h1>Latest News (ISR 60s)</h1>
      <ul>
        {news.map((item: any) => (
          <li key={item.id}>{item.title}</li>
        ))}
      </ul>
    </main>
  );
}

Technical Explanation

  1. Incremental Static Regeneration (ISR) serves cached static HTML for 60 seconds before triggering background revalidation.
  2. Subsequent visitors receive instant cached HTML while Next.js fetches fresh data behind the scenes.
  3. Delivers static CDN speeds with dynamic data freshness.

Exercise 2: On-Demand ISR Revalidation via Server Actions

Scenario: Purge cached ISR pages instantly after a content editor updates a blog post using revalidatePath().

Requirements:

  1. Call revalidatePath('/blog/[slug]') inside Server Action.
Answer

Implementation

// app/actions/cms.ts
"use server";

import { revalidatePath } from "next/cache";

export async function publishPost(slug: string) {
  // Update post in CMS database...

  // Instantly purge static ISR cache for target post
  revalidatePath(`/blog/${slug}`);
}

Technical Explanation

  1. revalidatePath() purges the static ISR page cache on demand without waiting for time-based revalidation timers.
  2. Updates static CDN pages instantly after content mutations.
  3. Standard headless CMS integration pattern.

Exercise 3: Auditing ISR Cache Hit/Miss Headers

Scenario: Inspect x-nextjs-cache headers in HTTP responses to verify ISR cache status (HIT, STALE, REVALIDATE).

Requirements:

  1. Describe x-nextjs-cache response header states.
Answer

Implementation

ISR Response Header Inspection:
- x-nextjs-cache: HIT        -> Served directly from static cache.
- x-nextjs-cache: STALE      -> Served stale cache; background revalidation triggered.
- x-nextjs-cache: REVALIDATED-> Fresh page generated after revalidation completed.

Technical Explanation

  1. Next.js attaches x-nextjs-cache headers to HTTP responses to indicate static cache status.
  2. Helps developers debug ISR revalidation behavior in production environments.
  3. Empirical verification of ISR caching.


7. Key Takeaways

  • ISR allows you to update static pages in the background without rebuilding the entire app.
  • It uses the Stale-While-Revalidate pattern: the first user after the cache expires gets old data, but triggers a background rebuild for future users.
  • It can also be used to generate completely new pages on-the-fly that weren't known at build time.
  • In the App Router, ISR is activated by setting a revalidate timer on data fetches or exporting the revalidate route segment config.
Built with LogoFlowershow