Understanding Incremental Static Regeneration (ISR)
Incremental Static Regeneration (ISR) is a hybrid rendering method that allows you to create or update static pages after you’ve built your site. It solves the biggest problem of Static Site Generation (SSG): the need to rebuild the entire application just to change a typo or update a product price.
With ISR, you can retain the benefits of static (fast, cached, secure) while ensuring your users see relatively fresh content. It works by regenerating specific pages in the background as traffic comes in.
The ISR Execution Flow
ISR uses a "stale-while-revalidate" strategy:
- Initial Request: The first user to visit a page sees the cached (stale) version immediately.
- Background Regeneration: If the cache has expired (based on a time you define), Next.js triggers a regeneration of that specific page in the background.
- Subsequent Requests: While the page is regenerating, other users still see the old cached version.
- Cache Update: Once the regeneration is successful, the old cache is invalidated and replaced with the new version.
- Fresh Content: The next user to visit the page sees the updated content.
When Should You Use ISR?
ISR is the perfect middle ground for large-scale applications that need both performance and data freshness.
1. Large E-commerce Sites
Imagine a store with 100,000 products. Building all of them statically takes hours. With ISR, you can build the most popular 1,000 products at build time and let the rest be generated on-demand when a user visits them. Plus, when a price changes, the page updates automatically after a short interval.
2. Content-Heavy Blogs or News Sites
For a news site, you want articles to load instantly (static), but you also might need to fix a typo or update a headline 10 minutes after publishing. ISR handles this automatically without a manual redeploy.
3. User-Generated Content
If you have public profiles or community posts that don't change every second but need to be indexable and fast, ISR allows you to serve them statically while keeping them reasonably up-to-date.
When Should You Avoid ISR?
ISR is powerful, but it's not a magic bullet for everything.
1. Real-Time Data Requirements
If your data must be 100% accurate at all times (e.g., a banking dashboard, stock trading interface, or ticket inventory), ISR is risky because users might see data that is a few seconds or minutes old. Use SSR or CSR instead.
2. Personalized Content
ISR caches the page globally for all users. You cannot use ISR to serve a page that says "Welcome, Yash" because that same cached HTML would be shown to "Alice" and "Bob." For personalization, use SSR or client-side fetching on top of a static shell.
🛠️ Implementing ISR in Next.js
Adding ISR to a Next.js application is incredibly simple—often just one line of code.
ISR Example: Pages Router
In the Pages Router, you simply add a revalidate property to the object returned by getStaticProps.
// pages/isr-page.tsx
import type { GetStaticProps } from "next";
type Product = {
id: string;
price: number;
};
export const getStaticProps = (async () => {
const res = await fetch("https://api.example.com/products/1");
const product: Product = await res.json();
return {
props: {
product,
},
// Next.js will attempt to re-generate the page:
// - When a request comes in
// - At most once every 60 seconds
revalidate: 60,
};
}) satisfies GetStaticProps<{ product: Product }>;
export default function ProductPage({ product }: { product: Product }) {
return (
<div>
<h1>Product Price: ${product.price}</h1>
<p>This page is statically generated but updates every minute.</p>
</div>
);
}ISR Example: App Router (Modern)
In the App Router, you configure ISR directly in your fetch call using the next.revalidate option.
// app/products/[id]/page.tsx
async function getProduct(id: string) {
const res = await fetch(`https://api.example.com/products/${id}`, {
next: {
// Revalidate this data request every 60 seconds
revalidate: 60,
},
});
return res.json();
}
export default async function Page({ params }: { params: { id: string } }) {
const product = await getProduct(params.id);
return (
<main className="p-8">
<h1 className="text-3xl font-bold">Product Details</h1>
<div className="mt-4 p-4 border rounded shadow-sm">
<p className="text-xl">
Price:{" "}
<span className="font-bold text-green-600">${product.price}</span>
</p>
<p className="text-sm text-gray-500 mt-2">
Data freshness: ~60 seconds
</p>
</div>
</main>
);
}On-Demand Revalidation
Sometimes waiting 60 seconds isn't good enough (e.g., a CMS webhook tells you content changed now). Next.js supports On-Demand ISR, where you can manually purge the cache for a specific path via an API call.
// app/api/revalidate/route.ts
import { revalidatePath } from "next/cache";
import { NextRequest } from "next/server";
export async function POST(request: NextRequest) {
const path = request.nextUrl.searchParams.get("path");
if (path) {
revalidatePath(path);
return Response.json({ revalidated: true, now: Date.now() });
}
return Response.json({
revalidated: false,
now: Date.now(),
message: "Missing path to revalidate",
});
}Conclusion: The Best of Both Worlds 🌍
Incremental Static Regeneration is a game-changer for scaling static sites. It allows you to keep your build times fast and your architecture simple, while still delivering content that feels dynamic to your users.
By mastering CSR, SSR, SSG, and ISR, you have a complete toolkit to architect any web application for optimal performance and user experience.