Part 73: Implementing On-Demand Revalidation in Next.js: A Step-by-Step Guide

[App] Dynamic Rendering and Revalidation

[App] Dynamic Rendering and Revalidation

Keeping your web application in sync with content changes from a CMS like Strapi is crucial for maintaining up-to-date information. On-demand revalidation in Next.js provides a powerful solution by allowing you to update pages immediately when CMS data changes. In this blog post, we'll walk through how to implement and test this feature effectively.

Receiving Notifications from the CMS

To achieve on-demand revalidation, we first need to set up a system where our Next.js application can receive notifications from the CMS whenever data changes. This is typically done using webhooks.

Setting Up the Webhook

  1. Create a Route Handler: First, we define a route in our Next.js application that will handle incoming webhook notifications.

    // app/webhooks/cms-event/route.js
    import { revalidateTag } from 'next/cache';
    import { CACHE_TAG_REVIEWS } from '@/lib/reviews';
    
    export async function POST(request) {
      const payload = await request.json();
      console.log('payload:', payload);
      if (payload.model === 'review') {
        revalidateTag(CACHE_TAG_REVIEWS);
        console.log('revalidated:', CACHE_TAG_REVIEWS);
      }
      return new Response(null, { status: 204 });
    }
  2. Test the Webhook: Initially, we can trigger the webhook manually from the CMS to ensure it's working correctly. This involves sending a POST request to the route handler and checking the server logs for the payload.

Handling Real Changes

Let's explore what happens when we make actual changes in the CMS:

  1. Delete an Entry: If we delete an entry, the webhook sends a notification with the event type entry.delete.

  2. Create a New Entry: Duplicating an entry triggers an entry.create event. If the entry is unpublished, the publishedAt field is null.

  3. Publish an Entry: Publishing a draft triggers two notifications: entry.update and entry.publish.

Filtering Relevant Events

To optimize revalidation, our route handler only triggers revalidation for specific models. In this example, we focus on changes related to "reviews":

if (payload.model === 'review') {
  revalidateTag(CACHE_TAG_REVIEWS);
}

Triggering Revalidation

The core of on-demand revalidation involves calling revalidateTag with a specific tag that identifies the cached data to be invalidated:

  1. Define a Cache Tag: In your data-fetching logic, use a tag to label cache entries:

    // lib/reviews.js
    export const CACHE_TAG_REVIEWS = 'reviews';
    
    async function fetchReviews(parameters) {
      const response = await fetch(url, {
        next: {
          tags: [CACHE_TAG_REVIEWS],
        },
      });
      // Handle response...
    }
  2. Invalidate Cache: The revalidateTag function marks the cache associated with the tag as invalid, prompting Next.js to regenerate pages upon the next request.

Testing On-Demand Revalidation

To test this setup:

  1. Build the Application: Perform a production build since revalidation cannot be tested in the development server.

  2. Simulate CMS Changes: Modify entries in the CMS to trigger the webhook and observe the logs to ensure revalidateTag is called.

  3. Check Page Updates: Reload the relevant pages in the browser. Initially, the old data may be served, but subsequent reloads should reflect the updated content.

Conclusion

By implementing on-demand revalidation, you ensure that your Next.js application stays in sync with CMS changes efficiently. This approach minimizes unnecessary re-renders and optimizes server resources by only regenerating pages when needed. With the webhook and cache-tagging setup, your application can dynamically respond to CMS updates, providing a seamless experience for users and administrators alike.

Last updated