Next.js Curriculum
MediumRendering Paradigms100% Free25 min read

Incremental Static Regeneration (ISR) Internals

The 30-Second Interview Answer

ISR enables static pages to update incrementally in the background without rebuilding the entire application. When a request arrives after the revalidation window, the edge CDN serves the stale cache immediately while triggering a background worker. Upon successful render, the cache is updated atomically.

Learning Objectives

Trace the lifecycle of a request during hit, stale, and background regeneration phases.

Explain cache header propagation (s-maxage, stale-while-revalidate) across CDNs.

Implement time-based versus on-demand cache invalidation via revalidateTag and revalidatePath.

Design fault-tolerant fallback strategies when background regeneration fails.

Prerequisites & Background Knowledge
SSG build mechanicsHTTP caching headersEdge CDN architecture

Why Interviewers Care

Standard system-design and performance question for high-traffic content and e-commerce platforms.

The Challenge

Explain the exact step-by-step request flow of ISR when multiple concurrent requests arrive after the revalidation threshold has expired. How does Next.js guarantee atomic cache updates?

Code Architecture & Implementation

1// Route Segment Configuration: Revalidate this page every 120 seconds
2export const revalidate = 120;
3
4export default async function BlogPostPage({ params }: { params: Promise<{ slug: string }> }) {
5 const { slug } = await params;
6
7 // Data fetch inherits the route revalidation interval or overrides it
8 const post = await fetch(`https://api.cms.com/posts/${slug}`, {
9 next: { tags: [`post-${slug}`, 'posts'] }
10 }).then(res => res.json());
11
12 return (
13 <article>
14 <h1>{post.title}</h1>
15 <time dateTime={post.updatedAt}>{post.updatedAt}</time>
16 <div dangerouslySetInnerHTML={{ __html: post.content }} />
17 </article>
18 );
19}
20
21// On-demand invalidation via Route Handler (e.g. CMS Webhook)
22// app/api/revalidate/route.ts
23import { revalidateTag } from 'next/cache';
24import { NextRequest, NextResponse } from 'next/server';
25
26export async function POST(req: NextRequest) {
27 const secret = req.nextUrl.searchParams.get('secret');
28 if (secret !== process.env.REVALIDATION_SECRET) {
29 return NextResponse.json({ message: 'Invalid token' }, { status: 401 });
30 }
31
32 const tag = req.nextUrl.searchParams.get('tag');
33 if (tag) {
34 revalidateTag(tag); // Purges cache across edge CDNs on demand
35 return NextResponse.json({ revalidated: true, tag });
36 }
37
38 return NextResponse.json({ message: 'Missing tag' }, { status: 400 });
39}

Architectural Explanation

ISR Execution Lifecycle Under Concurrent Load

Assume a route configured with revalidate = 60:

  1. $t = 0s$ (Build Time): Page is pre-rendered and stored in the Data Cache / CDN edge storage.
  2. $t = 30s$ (Cache Hit): User A requests the page. The CDN returns the cached HTML in <20ms.
  3. $t = 61s$ (Cache Stale): User B requests the page.
    • The edge immediately serves the stale cached HTML to User B (no delay).
    • Next.js detects the page is past its 60s threshold and schedules an asynchronous background regeneration task.
  4. $t = 61.2s$ (Cache Stampede Mitigation): Users C, D, and E arrive while the background task is executing.
    • They continue to receive the stale cached HTML.
    • Next.js deduplicates regeneration requests; only one background build executes at a time.
  5. $t = 61.8s$ (Atomic Swap): The background build completes successfully.
    • The new HTML and RSC payloads are written to storage atomically.
    • Subsequent requests (User F at $t = 62s$) receive the newly generated page.
  6. Failure Resilience: If the database query at $t = 61.5s$ throws an exception, the background build fails silently, and the existing cached page remains active until the next attempt succeeds.

Common Mistakes & Anti-Patterns

Expecting the first user after the revalidation window to see the new data immediately.

Using short revalidation intervals (e.g. 1 second) in high-traffic sites without rate limiting, causing unnecessary database load.

Forgetting that on-demand revalidation requires secure authentication (webhook secret token) to prevent denial-of-service cache wiping.

Interview Follow-Up Traps

Interviewer asks: "If an ISR page is requested 100,000 times in 1 minute, will the database be queried 100,000 times?" Trap answer: Yes, if revalidate is low. Correct answer: No. It is queried at most once per revalidation interval, regardless of traffic volume.

Interviewer asks: "How does ISR work in a multi-region containerized Docker environment without Vercel?" Trap answer: It cannot work. Correct answer: Next.js supports custom cache handlers (e.g. @neshca/cache-handler with Redis or S3) to synchronize the Data Cache across distributed Docker containers.

Frequently Asked Questions

What is the difference between time-based ISR and on-demand ISR?

Time-based ISR revalidates automatically after a specified duration expires. On-demand ISR revalidates immediately upon programmatic invocation of revalidateTag() or revalidatePath(), typically triggered by a CMS webhook.

By default, Next.js stores ISR pages on the local server filesystem under .next/cache. In multi-container setups, an external cache handler using Redis or shared storage is required.

Yes. generateStaticParams pre-builds high-priority pages at build time, and ungenerated pages can be generated on-demand and cached via ISR when first requested.

Any path not returned by generateStaticParams will immediately return a 404 response instead of generating on demand.

Yes, if revalidatePath("/blog/[slug]", "page") is called, all pages matching that segment are marked stale.