29

I have a product page at /products/[slug].js

and I use Incremental Static Generation for a wordpress/graphql site:

export async function getStaticProps(context) {

    const {params: { slug }} = context

    const {data} = await client.query(({
        query: PRODUCT_SLUG,
        variables: { slug }
    }));

    return {
        props: {
            categoryName: data?.productCategory?.name ?? '',
            products: data?.productCategory?.products?.nodes ?? []
        },
        revalidate: 1
    }

}

export async function getStaticPaths () {
    const { data } = await client.query({
        query: PRODUCT_SLUGS,
    })

    const pathsData = []

    data?.productCategories?.nodes && data?.productCategories?.nodes.map((productCategory) => {
        if (!isEmpty(productCategory?.slug)) {
            pathsData.push({ params: { slug: productCategory?.slug } })
        }
    })

    return {
        paths: pathsData,
        fallback: true,
    }
}

Everything works as expected except one thing. If I delete a product from wordpress which was previously published, NextJs serves the cached page instead of showing 404 - Not found page, and I think this is how it is supposed to work, meaning that if something isn't rebuilt, show the previous (stale) page.

But how can I completely remove the cache for a specific product which has been deleted and it is not fetched again from the PRODUCT_SLUGS query ?

I have read the fallback options: true, false, blocking but none of them seems to work.

Is there a solution to this, either a next.config.js configuration or another work around ?

juliomalves
  • 42,130
  • 20
  • 150
  • 146
entropyfeverone
  • 1,052
  • 2
  • 8
  • 20
  • 1
    This seems to be a popular question. You may check these threads (not sure if they'll work for you): [How to clear NextJs GetStaticPaths cache / “unpublish” a dynamic route?](https://stackoverflow.com/q/65526754/11613622), [Next.js ISR page not being deleted after deleting it in CMS](https://stackoverflow.com/q/67864802/11613622). PS: I just saw you posted an answer to one of them. Consider closing your question in favor of the answers present there. – brc-dd Jul 19 '21 at 18:24
  • 1
    This is now possible in Next.js v12.1 See my answer, here https://stackoverflow.com/a/71559884/4453486 – David B Mar 22 '22 at 12:16

3 Answers3

15

To clear the cache in Next.js app, follow these steps:

  1. Stop the development server or any running Next.js processes.
  2. Locate the root directory of your Next.js project.
  3. Delete the .next directory. You can do this using the command line or file explorer.

Info: Once the .next directory is deleted, you can start the Next.js development server or rebuild your project, and Next.js will regenerate the necessary cache and build artifacts. Keep in mind that deleting the .next directory will remove all the cached data and build artifacts, which means Next.js will need to rebuild the project and regenerate the cache on the next build or server start.

Sebastian Voráč MSc.
  • 3,256
  • 1
  • 18
  • 25
2

So I ran into this same issue, although I am using GraphCMS. So here is what you need to do to fix:

    export async function getStaticProps(context) {
    const {params: { slug }} = context

    const {data} = await client.query(({
        query: PRODUCT_SLUG,
        variables: { slug }
    }));

    if (!data) {
        return {
            notFound: true
        }
    } else {
        return {
            props: {
                categoryName: data?.productCategory?.name ?? '',
                products: data?.productCategory?.products?.nodes ?? []
            },
            revalidate: 1
        }
    }
}

You need to return notFound: true in getStaticProps

notFound - An optional boolean value to allow the page to return a 404 status and page.

See this page in the docs https://nextjs.org/docs/basic-features/data-fetching#getstaticprops-static-generation

Then in getStaticPaths change fallback to fallback: "blocking". If you keep fallback: true it is going to serve the stale page since that built successfully.

1

I think this is possible starting from next@12.1.x using this feature On-demand Incremental Static Regeneration https://nextjs.org/blog/next-12-1#on-demand-incremental-static-regeneration-beta

basically you can define an api path in this way

// 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' })
  }
  const PRODUCT_SLUGS = req.query.product_slug;

  try {
    await res.unstable_revalidate(`/products/${PRODUCT_SLUGS}`)
    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')
  }
}

Using this api path you can invalidate the cache for a specific product

dna
  • 2,097
  • 1
  • 11
  • 35