Menu

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.

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:

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.

pages/api/revalidate.js
export default async function handler(request, response) {
  // Check for secret to confirm this is a valid request
  if (request.query.secret !== process.env.MY_SECRET_TOKEN) {
    return response.status(401).json({ message: 'Invalid token' });
  }
 
  try {
    // This should be the actual path, not a rewritten path
    // e.g. for "/blog-posts/[slug]" this should be "/blog-posts/1"
    await response.revalidate('/blog-posts');
    return response.json({ revalidated: true });
  } catch (err) {
    // If there was an error, Next.js will continue
    // to show the last successfully generated page
    return response.status(500).send('Error revalidating');
  }
}
pages/api/revalidate.ts
import type { NextApiRequest, NextApiResponse } from 'next';
 
export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse,
) {
  // Check for secret to confirm this is a valid request
  if (req.query.secret !== process.env.MY_SECRET_TOKEN) {
    return res.status(401).json({ message: 'Invalid token' });
  }
 
  try {
    // This should be the actual path, not a rewritten path
    // e.g. for "/blog-posts/[slug]" this should be "/blog-posts/1"
    await res.revalidate('/blog-posts');
    return res.json({ revalidated: true });
  } catch (err) {
    // If there was an error, Next.js will continue
    // to show the last successfully generated page
    return res.status(500).send('Error revalidating');
  }
}
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(),
  });
}
app/api/revalidate/route.js
import { revalidatePath } from 'next/cache';
 
export async function GET(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(),
  });
}

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


Was this helpful?

supported.