Ever since Next.js 9.5 released Incremental Static Regeneration, On-demand ISR has been my most requested feature. Finally, we have the good news now. Next.js has released On-demand ISR (Beta) in the latest v12.1 release. In this article, we will look into the implementation of On-demand ISR.

Little Background of ISR

For those unfamiliar with this term, we will explain what ISR is and what benefits it brought to the table. If you have worked with Next.js, you might be familiar with the term SSG (Static Site Generation) using the function getStaticProps. ISR is an add-on on top of getStaticProps where it adds functionality to revalidate where Next.js re-generates the page after the revalidation timer and purges the cache whenever that page is requested.

To use ISR, we will implement a small example application that would consume a JSON users array using the mock API website https://mockapi.io/. I have generated a sample Next.js application using create-next-app, which sets up everything automatically for you. Inside the index.js file I replace the sample code with the below code

import Head from "next/head";
import styles from "../styles/Home.module.css";

export async function getStaticProps(context) {
  const res = await fetch(
    "https://6215cb41c9c6ebd3ce31d9f8.mockapi.io/mock/users"
  );
  const users = await res.json();
  return {
    props: {
      users,
    }, // will be passed to the page component as props
    revalidate: 10, // In seconds
  };
}

export default function Home({ users }) {
  return (
    <div className={styles.container}>
      <Head>
        <title>On Demand ISR</title>
        <meta name="description" content="On Demand ISR" />
        <link rel="icon" href="/favicon.ico" />
      </Head>

      <main>
        {users.map((user) => (
          <p key={user.id}>{user.name}</p>
        ))}
      </main>
    </div>
  );
}

Please note the key revalidate inside the return statement. This key specifies the time in seconds after which Next.js regenerates the page for the latest version. This apparently means that someone visiting the website first time after the data updates would see an older version and anyone opening that website after 10seconds would get the latest version of the page.

Downsides of this approach

While this approach was a boon for updating the generated pages after build but it has some downsides.

  1. If data updates on the backend, the very first user and the any other user who falls in the revalidate time range would still see the old cached version of the page.
  2. If the backend data doesn't update frequently, revalidating and re-generating the page every 10 second on a page load makes no sense and is a waste of resources.

Next.js 12.1 to the rescue

Next.js team heard the feedback and understood the need for an On-demand ISR where you can programmatically ask Next.js to purge the page cache rather than relying on revalidate timer. The benefit of this approach is that you can trigger this directly from your backend whenever the data changes and it would prevent all those un-necessary re-generations.

Next.js now exposes a function unstable_revalidate() that allows you to revalidate individual pages that use getStaticProps. Let's see how we can implement this in Next.js code.

First of all, remove the revalidate key from the return statement inside getStaticProps. Next, we need to create a webhook/API serverless function inside the api folder in our Next.js code.

Let's name the file revalidate.js.

// pages/api/revalidate.js

export default async function handler(req, res) {
  // 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 {
    await res.unstable_revalidate('/')
    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')
  }
}

This serverless function uses unstable_revalidate() which takes the page path as a parameter. It is the path of the page to be purged from the cache and returns a JSON success message.

I have commented out authentication on top of this function for testing purposes, but when you are in a production environment, it is a must to have authentication to prevent any unauthorized access to this function.

You can test this out on local by doing the following steps:

  1. Implement a page that uses data from the API (You can use mockapi for demo)
  2. Run next build and then next start.
  3. Update the data on the backend and call the revalidate API from the browser or Postman.
  4. Reload the page again, you would see the updated data on the frontend.

There you go, you have a perfect combo of SSG + On-demand re-generation.

You can check out the code for this article on my github.


Do write down your reviews or send in a mail from the contact form if you have any doubts and do remember to subscribe below for more content like this.