Skip to content
Now accepting new projects — limited slots available. Get started →
Architecture · Updated Jul 30, 2026

What is Incremental Static Regeneration (ISR)?

Incremental Static Regeneration (ISR) is a rendering strategy that rebuilds static pages in the background after a configurable revalidation interval.

What is Incremental Static Regeneration (ISR)?

Incremental Static Regeneration is a rendering strategy Vercel shipped in Next.js 9.5 (July 2020) that lets you serve pre-built static pages while regenerating them in the background after a configurable time interval. When someone requests a page whose revalidate window has elapsed, they get the existing cached version immediately (stale-while-revalidate pattern), and a fresh version generates behind the scenes for the next visitor. You get the performance of static HTML—sub-50ms TTFB from a CDN edge—without running a full site rebuild every time content changes. ISR works well for large content sites with tens of thousands of pages, like e-commerce catalogs or blog networks, where full static generation at build time would take minutes or hours.

How it works

ISR relies on two core mechanisms: a revalidation timer and background regeneration.

  1. Build time: Pages are statically generated at build, just like standard SSG. Each page opts into ISR by exporting a revalidate value (in seconds).
  2. Request time: The CDN serves the cached HTML. If the page is older than revalidate seconds, the current (stale) version still goes to the user, but the server triggers a background regeneration.
  3. Regeneration: The server re-runs getStaticProps (or the App Router equivalent), fetches fresh data, renders new HTML, and atomically replaces the cached version.
  4. Next request: The subsequent visitor gets the freshly generated page.

In the Next.js App Router (13+), ISR is configured via the route segment config:

// app/products/[slug]/page.tsx
export const revalidate = 60; // regenerate at most every 60 seconds

export default async function ProductPage({ params }: { params: { slug: string } }) {
  const product = await getProduct(params.slug);
  return <ProductDetail product={product} />;
}

For pages not generated at build time, you can use dynamicParams = true (the default) so ISR generates them on the first request and caches them from that point forward. This replaced the old fallback: true behavior from getStaticPaths.

On Vercel's infrastructure, the regenerated HTML is distributed to edge nodes automatically. Self-hosted Next.js deployments need a persistent cache store—the default filesystem cache works on a single server, but multi-server setups require a custom cache handler (Redis, S3, etc.).

When to use it

ISR sits between full static generation and server-side rendering. It's the right call in specific scenarios.

Use ISR when:

  • You have content that updates periodically but doesn't need real-time freshness (product listings, blog posts, documentation)
  • Your site has thousands of pages and full rebuilds take more than a few minutes
  • You want CDN-level performance without giving up data freshness
  • Your CMS publishes on a schedule and a 60–300 second staleness window is acceptable

Skip ISR when:

  • Content must be real-time (stock prices, live scores)—use SSR or client-side fetching
  • You need instant cache purge on publish—use on-demand revalidation (revalidateTag / revalidatePath) instead of time-based ISR
  • Your site is small enough (under ~500 pages) that a full rebuild in CI completes in under 30 seconds—plain SSG is simpler
  • You're self-hosting across multiple servers without a shared cache layer

ISR vs alternatives

Strategy Freshness TTFB Build time Complexity
SSG Stale until next build ~20-50ms (CDN) Scales with page count Low
ISR (time-based) Stale up to revalidate seconds ~20-50ms (CDN, cache hit) Constant (pages built on demand) Medium
On-demand revalidation Fresh on publish event ~20-50ms (CDN, after revalidation) Constant Medium-high (webhook setup)
SSR Always fresh ~100-500ms+ (origin) None Medium
Edge SSR Always fresh ~50-150ms None High

In practice, we often combine ISR with on-demand revalidation on the same project. ISR acts as a safety net (the floor freshness guarantee), while CMS webhooks calling revalidatePath provide near-instant updates when editors publish. We've shipped this pattern on 50+ projects and it covers the vast majority of content site needs.

Real-world example

We built a Next.js 14 App Router site for a B2B SaaS company with ~12,000 documentation pages sourced from a headless CMS. Full SSG builds were taking 18 minutes. After switching to ISR with revalidate = 120 and generating only the top 500 pages at build time, build duration dropped to under 90 seconds. The remaining pages were generated on first request and cached. We added a webhook from the CMS that calls revalidatePath('/docs/[slug]') on publish, so editors see updates within seconds. Average TTFB from Vercel's edge: 38ms on cache hit. Lighthouse performance scores stayed consistently at 95+.

Frequently asked questions about Incremental Static Regeneration (ISR)

Is ISR the same as on-demand revalidation?
No. ISR (time-based) regenerates pages automatically after a `revalidate` interval elapses — the trigger is time plus a visitor request. On-demand revalidation uses `revalidatePath` or `revalidateTag` to explicitly purge and regenerate a page in response to an event, like a CMS webhook. They solve different problems: ISR guarantees a maximum staleness window without any external triggers, while on-demand revalidation gives you instant freshness when you know content has changed. In most production setups, you want both — ISR as the baseline and on-demand revalidation for publish events.
When did ISR become standard?
ISR was introduced in Next.js 9.5 in July 2020 as a Pages Router feature via `getStaticProps` with a `revalidate` key. It became the de facto rendering strategy for content-heavy Next.js sites by 2021. With the App Router in Next.js 13 (October 2022), ISR was simplified to a `revalidate` export on route segments. As of April 2026, ISR is a stable, production-proven feature in Next.js 15. Other frameworks have adopted similar patterns — Nuxt 3 has `routeRules` with SWR-style caching, and Astro added server islands with similar stale-while-revalidate behavior.
What's the alternative to ISR?
The main alternatives are full SSG (rebuild everything on each deploy), SSR (render every request on the server), and on-demand revalidation (purge specific pages via API calls). For small sites, full SSG with fast CI builds is simpler and has zero staleness. For real-time data, SSR or edge SSR is the right call. If you're outside the Next.js ecosystem, Cloudflare Workers with KV or R2 caching can replicate the stale-while-revalidate pattern manually, and frameworks like SvelteKit and Nuxt offer their own equivalents with different APIs.
Does ISR work when self-hosting Next.js?
Yes, but with caveats. On a single server, the default filesystem-based cache works fine out of the box. The challenge is multi-server or containerized deployments where each instance has its own filesystem — one server might regenerate a page while others still serve the old version. To fix this, you need a shared cache handler. Next.js 14+ supports custom `cacheHandler` configuration, and the community has built adapters for Redis, S3, and other shared stores. On Vercel, this is handled automatically. If you're on AWS with multiple containers, plan for the shared cache layer upfront — it's the most common gotcha we see in self-hosted ISR setups.
Get in touch

Let's build
something together.

Whether it's a migration, a new build, or an SEO challenge — the Social Animal team would love to hear from you.

Get in touch →