Designly Blog

Next.JS - How to Implement Incremental Static Regeneration (ISR)

Next.JS - How to Implement Incremental Static Regeneration (ISR)

Posted in Full-Stack Development by Jay Simons
Published on June 5, 2022

We all love Next.JS for its ability to render static pages for our dynamic content. Previously, when new content was added, one had to completely rebuild the site, but no longer!

Introducing: Incremental Static Regeneration, or ISR. ISR allows only a specific page to regenerate in the background when changes are detected. There are two ways to implement this feature: automatic regeneration and on-demand regeneration. I will cover both methods.


Automatic Regeneration

Automatic regeneration is handled by the Next functions getStaticProps() and getStaticPaths(). To implement ISR, we only have to worry about two lines of code:

/* [slug].js */

export async function getStaticProps({ params }) {
    const res = await getPost(params.slug)

    return {
        props: {
            post: res[0].fields
        },
        revalidate: 10 // Revalidate max 10 seconds
    }
}

export async function getStaticPaths() {
    const slugs = await getPostSlugs();

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

    return {
        paths,
        fallback: 'blocking' // SSR page and then cache
    };
}

I've added the revalidate: 10 directive to getStaticProps(). This means that stale content will only be displayed for a maximum of 10 seconds, and then is revalidated and rebuilt in the background. The next refresh after this time expires will display the current content.

In getStaticPaths(), I've set fallback to blocking. What this does is, if the current path does not exist, it is Server-Side Rendered. Subsequent renders will be served from the cache from then on.

That's it! It's that simple.


On-Demand ISR

You may want to consider on-demand ISR, especially if you want new content to be live immediately. Let's say you have an eCommerce store and you want to change the price of a product. We'll create an API path that will allow us to regenerate a path or list of paths on demand. We'll use a secure API key to prevent abuse.

Here's the code for my API:

/* revalidate.js */

export default async function handler(req, res) {
    // Get our API key from 'authorization' header
    const bearer = req.headers['authorization'];
    if (!bearer) return res.status(401).json({ message: 'Unauthorized' })
    const key = bearer.split(" ").pop();

    // Compare given key to secret key
    if (key !== process.env.REVAL_SECRET) {
        return res.status(401).json({ message: 'Unauthorized' })
    }

    // Get paths array from POST request
    const paths = req.body.paths ?? null;
    if (!paths || typeof paths !== 'array') return res.status(400).json({ message: 'Bad Request: No paths specified' })

    try {
        paths.forEach(async (p) => {
            await res.unstable_revalidate(p)
        })
        return res.json({ revalidated: true })
    } catch (err) {
        // Catch error and serve 500
        return res.status(500).send('Error revalidating')
    }
}

Now we can test this by sending a request to the API:

/* Revalidate Request Example */

const axios = require('axios');

const postData = {
    paths: [
        '/blog',
        '/blog/post/blog-post-one',
        '/blog/post/blog-post-two'
    ]
}

const res = await axios({
    headers: {
        'Authorization': `Bearer ${process.env.REVAL_SECRET}`
    },
    method: 'POST',
    url: '/api/revalidate',
    data: postData
}).then((res) => {
    return res
}).catch((e) => {
    console.log(e);
});

That's all there is to it. This new(ish) feature has completely solidified my committment to Next.JS. I hope you feel the same way!

For more great information, please Visit Our Blog.


Loading comments...