Incremental Static Regeneration (ISR)
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
- Static Site Generation (SSG) — The foundation of ISR.
- Time-based Revalidation (
next.revalidate) — The data-fetching concept that powers ISR.
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:
- Build Time: Next.js generates the static HTML for
/productsand deploys it. - 0s - 60s: 1,000 users visit. They get the lightning-fast static HTML.
- 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.
- 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:
- Export
export const revalidate = 60inpage.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
- Incremental Static Regeneration (ISR) serves cached static HTML for 60 seconds before triggering background revalidation.
- Subsequent visitors receive instant cached HTML while Next.js fetches fresh data behind the scenes.
- 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:
- 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
revalidatePath()purges the static ISR page cache on demand without waiting for time-based revalidation timers.- Updates static CDN pages instantly after content mutations.
- 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:
- Describe
x-nextjs-cacheresponse 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
- Next.js attaches
x-nextjs-cacheheaders to HTTP responses to indicate static cache status. - Helps developers debug ISR revalidation behavior in production environments.
- Empirical verification of ISR caching.
6. Related Terms
- Time-based Revalidation (
next.revalidate) — The exact same concept, applied to data fetching. ISR is what happens when that concept is applied to the page rendering level. - On-Demand Revalidation (
revalidatePath,revalidateTag) — The alternative to time-based ISR for instant updates. - Static Site Generation (SSG) — Related concept: Static Site Generation (SSG).
- Content Delivery Network (CDN) & Edge Cache — Related concept: Content Delivery Network (CDN) & Edge Cache.
- Docker & Standalone Build — Related concept: Docker & Standalone Build.
generateStaticParamsFunction — generateStaticParams.
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
revalidatetimer on data fetches or exporting therevalidateroute segment config.