Incremental Static Regeneration (ISR) in Next.js: A Practical Overview

Table of contents

✅ What Is ISR?
Incremental Static Regeneration (ISR) allows you to:
Pre-render pages at build time like static sites
Regenerate those pages in the background after deployment
Serve static performance with dynamic freshness without a full rebuild
🏗️ What Happens at Build Time?
At build time, Next.js pre-generates all static pages defined using:
generateStaticParams()
(in App Router)getStaticPaths()
(in Pages Router)
These functions return the list of dynamic route parameters — typically things like:
Blog slugs (
/blog/my-first-post
)Product IDs (
/product/123
)User handles (
/profile/muraliSingh
)Example : App Router
// App Router export async function generateStaticParams() { const posts = await fetchPosts(); return posts.map(post => ({ slug: post.slug })); }
This tells Next.js to build and cache each of those pages at build time.
You don’t need to prebuild every possible route. Instead, only prebuild what's important like trending or recently updated content.
Pages without dynamic data or those with predefined slugs are written to HTML files and cached globally via Vercel’s Edge Network or similar CDN.
However, if a dynamic route is defined but its slug is not included in the prebuild list, that page won’t be built yet. When a user first visits it, Next.js will generate it on-demand using ISR and cache it for future requests.
🚀 What Happens at Runtime?
At runtime:
A user visits
/videos/[slug]
If the page was already built:
- Next.js serves the cached HTML instantly
If the page was not built:
Next.js builds it on-the-fly (ISR kicks in)
Caches the result for future requests
This is how on-demand static generation works behind the scenes.
🔁 How Revalidation Works
When you define a revalidation interval in a static route:
export const revalidate = 3600; // Rebuild every 1 hour
Here’s what happens:
Next.js serves a static HTML page from the CDN on every request.
For next 1 hour this cached page or content is given to the every request made to that cached page. After 1 hour, the cached page becomes stale, but is still served immediately to the user.
In the background, Next.js triggers a regeneration.
Once regeneration completes, the new HTML version replaces the old cached page but global cache replacement depends on your hosting provider.
For example, Vercel automatically propagates the updated cached page across all its CDN regions with no manual intervention.
On other providers, you may need to manually purge or configure cache invalidation to achieve the same effect..
🔧 On-Demand ISR: How Manual Revalidation Works Behind the Scenes
When content changes say, an admin updates a video’s details you often want to immediately refresh the cached page without waiting for the automatic revalidation interval.
Here’s how the process works in Next.js:
1. Admin Triggers Revalidation
The admin UI or backend calls a secure API route (often called a “revalidate endpoint”) to tell Next.js to regenerate a specific page.
This call typically includes a secret token (stored in an environment variable like
process.env.REVALIDATE_SECRET
) to authenticate and prevent unauthorized requests.await res.revalidate(`/videos/${slug}`);
2. API Route Validates the Request
//videos/api/revalidate.ts
import type {
NextApiRequest,
NextApiResponse
} from 'next';
export async function POST(req: NextApiRequest, res: NextApiResponse) {
const secret = req.headers['x-revalidate-secret'];
// Check for secret to confirm this is a valid request
if (secret !== process.env.REVALIDATE_SECRET) {
return res.status(401).json({
message: 'Invalid token'
});
}
const {
slug
} = await req.json();
try {
// Trigger Next.js to regenerate the page for this slug
await res.revalidate(/videos/${slug});
return res.json({revalidated: true});
} catch (err) {
// If there was an error, Next.js will continue
// to show the last successfully generated page
return res.status(500).json({
message: 'Failed to revalidate'
});
}
}
3. Next.js Regenerates the Page
Next.js fetches fresh data from your database or API.
It renders the updated page server-side.
The new HTML replaces the stale cache (depending on your hosting provider, this can be immediate and global).
4. Subsequent Requests Get the Fresh Page
Users requesting
/videos/[slug]
will receive the updated content instantly.This avoids unnecessary delays or stale data.
Why Use a Secret Token?
To secure the revalidation endpoint from unauthorized access.
Prevents malicious users from forcing frequent regenerations or DOS attacks.
Only trusted systems (like your admin panel or backend) should call this endpoint.
Note: If you are using on-demand revalidation, you do not need to specify a revalidate
time inside of generateStaticParams()
(in App Router) or getStaticPaths()
(in Pages Router). Next.js will use the default value of false
.
This is called On-Demand ISR
⚙️ What Is Fallback?
fallback
is a setting that controls what should happen when a user requests a dynamic route that wasn’t prebuilt at build time.
Feature | Pages Router | App Router |
Where it's defined | getStaticPaths() | Implicit in generateStaticParams() |
fallback: false | ❌ Return 404 if the path isn’t prebuilt | ❌ Not supported |
fallback: true | ✅ Show fallback UI first, then load data and render in client | ❌ Not supported |
fallback: blocking | ✅ Server waits, builds the page on-demand, then serves it as well as cache it. | ✅ Always the default |
- Use
'blocking'
when SEO, SSR consistency, or data loading is important.
📊 How It Helps Web Vitals
First Load (TTFB): Pages are served from the CDN as pre-rendered HTML — extremely fast response times, often under 50ms.
CLS/FID: Layouts are stable because there's no skeleton screen or late-injected content.
LCP: Since full content is already in the HTML (no loading spinners or client hydration delays), the largest element (e.g. image, title) appears faster.
🧠 When to Use ISR
Use Incremental Static Regeneration (ISR) when you want the best of both static performance and dynamic flexibility.
Fast-loading pages with content that updates infrequently (minutes, hours, or days)
SEO is important, but full rebuilds on every content change are too costly
You have many dynamic routes (e.g. blogs, products, videos, user profiles)
You want the performance of Static Generation (SSG) with the scalability of Server Rendering
You need editor/admin-triggered updates without redeploying the whole app
🚫 When to Avoid ISR
Avoid ISR if:
Content changes per request (user-specific)
You need real-time updates (like live sports scores, stock tickers, or chat apps)
Page depends on auth/session use SSR or CSR
🔀 Can ISR Be Combined With Other Rendering?
Absolutely. In fact, combinational rendering is often the most scalable and performance-optimized way to build large Next.js applications.
You don’t have to choose just ISR, you can mix and match ISR, SSR, CSR, and even static SSG based on the needs of each page or component.
💡 Best Practices for Combining:
Use ISR for content-heavy, SEO-relevant pages like blogs, products, tutorials.
Use SSR for pages that depend on session/auth data or change per request.
Use CSR inside components for real-time data (chat, notifications, live feeds).
Use SSG (static) for truly static routes like
/terms
,/about
,/pricing
.
🧵 Final Takeaway
Incremental Static Regeneration (ISR) is a game-changer in how we build and scale modern web applications. It combines the speed of static pages with the flexibility of dynamic content without compromising on SEO, performance, or developer experience.
Whether you are serving 100 pages or 1 million, ISR lets you:
Pre-render only what matters most
Update content without redeploying
Scale globally with minimal infrastructure
Blend with SSR and CSR for a hybrid architecture
🔁 Think of ISR as "Static Generation with a smart cache and a trigger."
It gives you control over when and how your content is updated automatically or on-demand.
⚡ Use it when speed matters, SEO counts, and updates aren’t per-request.
Subscribe to my newsletter
Read articles from Murali Singh directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Murali Singh
Murali Singh
Remote SWE | JavaScript | OpenSource Engineer | Loves to build scalable systems |