Getting started with ISR

Last updated April 9, 2025

This guide will help you get started with using Incremental Static Regeneration (ISR) on your project, showing you how to regenerate your pages without rebuilding and redeploying your site. When a page with ISR enabled is regenerated, the most recent data for that page is fetched, and its cache is updated. There are two ways to trigger regeneration:

  • Background revalidation – Regeneration that recurs on an interval
  • On-demand revalidation – Regeneration that occurs when you send certain API requests to your app

Background revalidation allows you to purge the cache for an ISR route automatically on an interval.

When using Next.js with the App Router, you can enable ISR by using the revalidate route segment config for a layout or page.

apps/example/page.ts
export const revalidate = 10; // seconds
export const revalidate = 10; // seconds
export async function getStaticProps() {
  /* Fetch data here */
 
  return {
    props: {
      /* Add something to your props */
    },
    revalidate: 10, // Seconds
  };
}
export async function getStaticProps() {
  /* Fetch data here */
 
  return {
    props: {
      /* Add something to your props */
    },
    revalidate: 10, // Seconds
  };
}
export const config = {
  isr: {
    expiration: 10,
  },
};
export const config = {
  isr: {
    expiration: 10,
  },
};
export default defineNuxtConfig({
  routeRules: {
    // This route will be revalidated
    // every 10 seconds in the background
    '/blog-posts': { isr: 10 },
  },
});
export default defineNuxtConfig({
  routeRules: {
    // This route will be revalidated
    // every 10 seconds in the background
    '/blog-posts': { isr: 10 },
  },
});

The following example renders a list of blog posts from a demo site called jsonplaceholder, revalidating every 10 seconds or whenever a person visits the page:

pages/blog-posts/index.ts
export async function getStaticProps() {
  const res = await fetch('https://api.vercel.app/blog');
  const posts = await res.json();
 
  return {
    props: {
      posts,
    },
    revalidate: 10,
  };
}
 
interface Post {
  title: string;
  id: number;
}
 
export default function BlogPosts({ posts }: { posts: Post[] }) {
  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  );
}
export async function getStaticProps() {
  const res = await fetch('https://api.vercel.app/blog');
  const posts = await res.json();
 
  return {
    props: {
      posts,
    },
    revalidate: 10,
  };
}
 
export default function BlogPosts({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  );
}
app/blog-posts/page.ts
export const revalidate = 10; // seconds
 
interface Post {
  title: string;
  id: number;
}
 
export default async function Page() {
  const res = await fetch('https://api.vercel.app/blog');
  const posts = (await res.json()) as Post[];
  return (
    <ul>
      {posts.map((post: Post) => {
        return <li key={post.id}>{post.title}</li>;
      })}
    </ul>
  );
}
export const revalidate = 10; // seconds
 
export default async function Page() {
  const res = await fetch('https://api.vercel.app/blog');
  const posts = await res.json();
 
  return (
    <ul>
      {posts.map((post) => {
        return <li key={post.id}>{post.title}</li>;
      })}
    </ul>
  );
}

To test this code, run the appropriate dev command for your framework, and navigate to the /blog-posts/ route.

You should see a bulleted list of blog posts.

On-demand revalidation allows you to purge the cache for an ISR route whenever you want, foregoing the time interval required with background revalidation.

To revalidate a page on demand with Next.js:

  1. Create an Environment Variable which will store a revalidation secret
  2. Create an API Route that checks for the secret, then triggers revalidation

The following example demonstrates an API route that triggers revalidation if the query paramater ?secret matches a secret Environment Variable:

app/api/revalidate/route.ts
import { revalidatePath } from 'next/cache';
 
export async function GET(request: Request) {
  const { searchParams } = new URL(request.url);
  if (searchParams.get('secret') !== process.env.MY_SECRET_TOKEN) {
    return new Response('Invalid credentials', {
      status: 401,
    });
  }
 
  revalidatePath('/blog-posts');
 
  return Response.json({
    revalidated: true,
    now: Date.now(),
  });
}

See the background revalidation section above for a full ISR example.

Now that you have set up ISR, you can explore the following:


Was this helpful?

supported.