---
title: Incremental Static Generation
description: An extension of SSG that regenerates individual pages in the background after deployment, keeping static performance while allowing content to update without a full rebuild.
tokens: ~635
---

# Incremental Static Generation

Incremental Static Generation (also called Incremental Static Regeneration, ISR) builds on [Static Site Generation](/docs/web/rendering/ssg). Pages are still pre-rendered at build time, but each page carries a revalidation interval. When a request arrives after the interval expires, the CDN serves the stale page immediately and triggers a background regeneration. The next visitor gets the freshly built version. This is the HTTP `stale-while-revalidate` pattern applied to full pages.

## How It Works

```
┌──────────┐     ┌───────┐      ┌──────────┐
│  Server  │     │  CDN  │      │ Browser  │
└────┬─────┘     └───┬───┘      └────┬─────┘
     │                │←── request ──│
     │                │ fresh?       │
     │                │ yes → cached →│
     │                │ no  → stale ─→│
     │←── rebuild ───│               │
     │── new HTML ──→│ (next request │
     │                │  gets update) │
```

Pages are generated at build time like SSG. Each has a `revalidate` time (e.g. 60 seconds). Within that window the CDN serves the cached file. After the window expires, the next request still gets the stale page (no latency penalty), but the server re-renders in the background and updates the cache.

## Next.js API

Adding `revalidate` to `getStaticProps` enables ISR:

```typescript
import type { GetStaticProps } from "next";

export const getStaticProps: GetStaticProps<{ product: Product }> = async ({ params }) => {
  const product = await fetchProduct(params!.id as string);
  return {
    props: { product },
    revalidate: 60,
  };
};
```

### On-Demand Revalidation

For cases where time-based staleness is unacceptable, an API call can immediately invalidate a specific page:

```typescript
import type { NextApiRequest, NextApiResponse } from "next";

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  await res.revalidate(`/products/${req.query.id}`);
  return res.json({ revalidated: true });
}
```

A CMS webhook can call this endpoint after a content editor publishes, so the page updates within seconds instead of waiting for the timer.

## Trade-offs

| Strength | Weakness |
| -------- | -------- |
| Static-level FCP and TTFB | Content can be stale for up to `revalidate` seconds (time-based) |
| Low server cost — regeneration once per interval, not per request | More infrastructure than plain SSG (needs a server for regeneration) |
| Shorter builds — only popular pages built upfront | On-demand revalidation requires wiring up webhooks or API calls |