Next.js Incremental Static Regeneration (ISR) lets you update static pages after deployment without rebuilding the entire site.

Let’s see it in action. Imagine a blog where new posts are added frequently. Rebuilding the whole site for each new post is slow and defeats the purpose of static generation. ISR solves this.

Here’s a pages/posts/[slug].js example using ISR:

import { useRouter } from 'next/router';

function PostPage({ post }) {
  const router = useRouter();

  // If the page is not yet generated, this will be displayed
  if (router.isFallback) {
    return <div>Loading...</div>;
  }

  return (
    <div>
      <h1>{post.title}</h1>
      <p>{post.content}</p>
      <p>Last updated: {new Date(post.updatedAt).toLocaleString()}</p>
    </div>
  );
}

export async function getStaticPaths() {
  // Fetch all post slugs
  const res = await fetch('https://api.example.com/posts');
  const posts = await res.json();

  const paths = posts.map((post) => ({
    params: { slug: post.slug },
  }));

  return { paths, fallback: true }; // fallback: true enables ISR
}

export async function getStaticProps({ params }) {
  // Fetch single post data
  const res = await fetch(`https://api.example.com/posts/${params.slug}`);
  const post = await res.json();

  // Pass post data to the page via props
  return {
    props: { post },
    revalidate: 60, // Re-generate this page at most once every 60 seconds
  };
}

export default PostPage;

In this setup:

  • getStaticPaths tells Next.js which paths to pre-render at build time. fallback: true is crucial for ISR.
  • getStaticProps fetches the data for each post. The revalidate: 60 option is the heart of ISR. It means Next.js will try to regenerate this page in the background at most once every 60 seconds if a request comes in.

The magic happens when a user requests a page that hasn’t been generated or whose revalidate period has expired.

  1. The user’s request is served immediately with the stale static page.
  2. In the background, Next.js triggers a regeneration of the page using getStaticProps.
  3. Once the regeneration is complete, subsequent requests will receive the fresh static page.

This hybrid approach offers the speed of static sites with the freshness of dynamic ones. You get static-site performance for most requests, but your content can update without redeploying your entire application.

The fallback option in getStaticPaths is key. When fallback: true, for any path not generated at build time, Next.js will serve a fallback version (like the "Loading…" state in the example) and then generate the page on the first request. For paths already generated, if the revalidate time has passed, the old page is served while a new one is built in the background. If you set fallback: 'blocking', the user will wait for the new page to be generated before it’s served, avoiding the "Loading…" state.

Most people understand revalidate as a simple timer. What’s actually happening is that Next.js maintains a cache of generated pages. When revalidate is set, it marks the page as "stale" after that duration. When a request comes in for a stale page, Next.js serves the existing static file and then queues up a background job to regenerate it. This background regeneration uses the same getStaticProps logic. Once the regeneration is complete, the new static file replaces the old one in the cache. This "stale-while-revalidate" strategy ensures users always get a fast response, even when content is updating.

The next concept to explore is how ISR interacts with client-side data fetching and how to handle dynamic routing with ISR in more complex scenarios.

Want structured learning?

Take the full Vercel course →