The Problem ISR Solves
Plain Static Site Generation freezes a page's HTML at build time; if underlying data changes, visitors keep seeing stale content until the site is rebuilt and redeployed. Incremental Static Regeneration (ISR) solves this by letting a statically generated page be regenerated in the background after a specified time window, without requiring a full site rebuild. In the App Router, this is enabled by passing a revalidate option to fetch, such as fetch(url, { next: { revalidate: 60 } }), which tells Next.js that cached data (and the page built from it) can be reused for up to 60 seconds before it's considered stale.
Cricket analogy: It's like a stadium's printed team-sheet board being reprinted fresh every hour during a long rain delay, rather than reprinting the whole match program from scratch or leaving yesterday's lineup posted all day.
Time-Based Revalidation
With time-based revalidation, the first request after the revalidate window expires still gets the old (stale) cached page instantly -- Next.js triggers a regeneration in the background at that point, and once the new HTML is ready, subsequent requests receive the fresh version. This stale-while-revalidate behavior means no visitor ever waits on a slow rebuild; they either get cached content or, shortly after, updated content, and the server load stays low because regeneration only happens occasionally rather than on every request.
Cricket analogy: It's like a scoreboard operator showing the last known score for a few more seconds while quickly confirming the actual update with the third umpire, rather than freezing the display blank while waiting.
// app/products/page.tsx -- time-based ISR
async function getProducts() {
const res = await fetch('https://api.example.com/products', {
next: { revalidate: 60 }, // regenerate at most once every 60 seconds
});
return res.json();
}
export default async function ProductsPage() {
const products = await getProducts();
return (
<ul>
{products.map((p: { id: string; name: string }) => (
<li key={p.id}>{p.name}</li>
))}
</ul>
);
}
// app/api/revalidate/route.ts -- on-demand revalidation via a webhook
import { revalidatePath } from 'next/cache';
import { NextRequest, NextResponse } from 'next/server';
export async function POST(request: NextRequest) {
const { path, secret } = await request.json();
if (secret !== process.env.REVALIDATE_SECRET) {
return NextResponse.json({ message: 'Invalid secret' }, { status: 401 });
}
revalidatePath(path);
return NextResponse.json({ revalidated: true, now: Date.now() });
}
On-demand revalidation using revalidatePath() or revalidateTag() lets you invalidate a specific page or a group of cached fetches the instant your data actually changes -- for example, triggered by a CMS webhook when an editor publishes a new article -- instead of waiting for a fixed time window to expire.
New Paths at Runtime
ISR also handles paths that weren't included in generateStaticParams() at build time. When a visitor requests a dynamic route path that wasn't pre-rendered, Next.js can generate it on that first request and then cache the result as a static page for subsequent visitors, controlled by the dynamicParams export (true by default). This is especially useful for large catalogs, like an e-commerce site with tens of thousands of products, where pre-building every single page at build time would make deploys impractically slow.
Cricket analogy: It's like a stadium print shop only pre-printing scorecards for the marquee fixtures of the season, but printing a scorecard on demand the first time anyone asks for an obscure domestic warm-up match, then keeping that copy for future requests.
Setting dynamicParams to false will cause Next.js to return a 404 for any path not returned by generateStaticParams() at build time, instead of generating it on demand. Only do this deliberately when you want to strictly limit which paths exist.
- ISR lets statically generated pages be regenerated after deployment without a full site rebuild.
- Time-based revalidation via { next: { revalidate: N } } serves stale content instantly while regenerating in the background.
- The stale-while-revalidate pattern means no visitor waits on a live rebuild; they get cached content, then fresher content soon after.
- revalidatePath() and revalidateTag() enable on-demand revalidation triggered by events like CMS webhooks.
- Paths not covered by generateStaticParams() can be generated on first request and cached, controlled by dynamicParams.
- ISR is ideal for large catalogs where pre-building every page at build time would be impractically slow.
- Setting dynamicParams to false restricts routes to only the paths explicitly pre-rendered at build time.
Practice what you learned
1. What core problem does Incremental Static Regeneration (ISR) solve compared to plain SSG?
2. In the fetch option { next: { revalidate: 60 } }, what does the number 60 represent?
3. In the stale-while-revalidate pattern used by ISR, what does a visitor see on the first request after the revalidation window expires?
4. What is the purpose of revalidatePath() or revalidateTag()?
5. What happens when a visitor requests a dynamic route path not included in generateStaticParams(), assuming dynamicParams is true (the default)?
Was this page helpful?
You May Also Like
Static Site Generation
Learn how Next.js pre-renders pages to static HTML at build time using Static Site Generation, and when it's the right rendering strategy.
Server-Side Rendering
Understand how Server-Side Rendering (SSR) generates HTML on every request in Next.js, and how it differs from static generation.
Streaming and Suspense
Learn how Next.js streams HTML from the server using React Suspense so pages can show content progressively instead of waiting on the slowest data fetch.
Related Reading
Related Study Notes in Web Development
Browse all study notesWebSockets Study Notes
Web Development · 30 topics
Web DevelopmentWebAssembly Study Notes
WebAssembly · 30 topics
Web DevelopmentgRPC Study Notes
Protocol Buffers · 30 topics
Web DevelopmentSpring Boot Study Notes
Java · 30 topics
Web DevelopmentFlask Study Notes
Python · 30 topics
Web DevelopmentDjango Study Notes
Python · 30 topics