How to automatically revalidate a page in NextJS?

Revalidate in Next.js 14 App Router is a powerful feature that lets you combine the performance benefits of static generation with the flexibility of dynamic data updates. It allows you to serve static pages and update them periodically without rebuilding your entire application. This is particularly useful when you want your pages to remain fast but still reflect updates in the content.

What is Revalidate?

In Next.js, revalidation is a process where a statically generated page is updated at a specified interval. This means that even though the page is built statically (at build time), it can be refreshed on the server at runtime without requiring a complete rebuild of your site.

For example, if you have a Recipe App where recipes are added frequently, you can use revalidate to keep the recipe listing page up-to-date by re-fetching new recipes every hour. This way, your app remains fast, and users always get fresh content.


Setting Up with Fetch Requests

Let’s start by implementing revalidate in a Recipe App for the recipe listing page. The goal here is to update the recipe listings every hour (3600 seconds) so users always see the latest recipes.

src/
└── app/
    └── recipes/
        └── page.tsx  # Recipe listing page using revalidate
// src/app/recipes/page.tsx
import { fetch } from 'next/navigation';

// Revalidate the page every hour (3600 seconds)
export const revalidate = 3600;

export default async function RecipesPage() {
  const recipes = await fetch('https://api.example.com/recipes', {
    next: { revalidate: 3600 }, // Revalidate the data every hour
  }).then(res => res.json());

  return (
    <section>
      <h2>Latest Recipes</h2>
      <ul>
        {recipes.map(recipe => (
          <li key={recipe.id}>{recipe.name}</li>
        ))}
      </ul>
    </section>
  );
}

Explanation:

  • The revalidate export ensures that this page is revalidated every 3600 seconds (1 hour). After each hour, the server will fetch the latest data from the API and update the page.
  • When a user visits the page, if it’s within the revalidation window, they get the cached version. If the page needs to be revalidated, the next user request will trigger a refresh.

Certainly! Let’s explain the complete scenario with a real-world example, showing how the Revalidate feature works in Next.js 14 by illustrating the state of the HTML before and after the revalidation period. The scenario revolves around a Recipe App that lists recipes, where the content updates every hour.

Initial State: Recipe Listings Before Revalidation

When the app is first built, the recipes are fetched from the API, and a static HTML page is generated. This page will be cached and served to all users for the next 3600 seconds.

Let’s assume that when the page is first built, the API returns the following recipes:

[
  { "id": "chocolate-cake", "name": "Chocolate Cake" },
  { "id": "pasta-alfredo", "name": "Pasta Alfredo" },
  { "id": "grilled-chicken", "name": "Grilled Chicken" }
]

Based on this data, the generated HTML would look like this:

HTML Output Before Revalidation (Initial Build):

<html lang="en">
  <body>
    <section>
      <h2>Latest Recipes</h2>
      <ul>
        <li><a href="/recipes/chocolate-cake">Chocolate Cake</a></li>
        <li><a href="/recipes/pasta-alfredo">Pasta Alfredo</a></li>
        <li><a href="/recipes/grilled-chicken">Grilled Chicken</a></li>
      </ul>
    </section>
  </body>
</html>

This HTML page is cached and served to all users for 3600 seconds (1 hour). If a user visits the /recipes page within this 1-hour window, they will see the cached version with the initial recipe list.

State After 1 Hour (Revalidation Triggered)

After 3600 seconds (1 hour), the revalidate interval expires, and the page needs to be refreshed. When the next user visits the /recipes page, the server will fetch new data from the API, regenerate the page, and then cache the updated version.

Let’s say after 1 hour, the API returns new recipes like this:

[
  { "id": "chocolate-cake", "name": "Chocolate Cake" },
  { "id": "pasta-alfredo", "name": "Pasta Alfredo" },
  { "id": "grilled-chicken", "name": "Grilled Chicken" },
  { "id": "vegan-burger", "name": "Vegan Burger" }
]

The server fetches this new data, and the page is re-generated with the new recipe ("Vegan Burger") added to the list.

HTML Output After Revalidation (Updated Page):

<html lang="en">
  <body>
    <section>
      <h2>Latest Recipes</h2>
      <ul>
        <li><a href="/recipes/chocolate-cake">Chocolate Cake</a></li>
        <li><a href="/recipes/pasta-alfredo">Pasta Alfredo</a></li>
        <li><a href="/recipes/grilled-chicken">Grilled Chicken</a></li>
        <li><a href="/recipes/vegan-burger">Vegan Burger</a></li>
      </ul>
    </section>
  </body>
</html>

Now, every user visiting the /recipes page will see the updated list with the new recipe (Vegan Burger) for the next 3600 seconds. The page is cached again and served to all users until the next revalidation period.

Revalidate a Page

// src/app/recipes/page.tsx
export const revalidate = 3600; // Revalidate every 1 hour

Revalidate a Layout

// src/app/layout.tsx
export const revalidate = 86400; // Revalidate every 24 hours

When to Use Revalidate

Revalidate is perfect for pages where the content changes periodically, but you still want the speed of static generation. It strikes a balance between performance and freshness, allowing you to update the data at defined intervals.

Use Case: Recipe Listings

In our Recipe App, the recipe listing page is a great candidate for revalidate. Recipes may not change constantly, but they do update throughout the day. Instead of rebuilding the entire site every time a new recipe is added, revalidation can refresh the recipe listing automatically at set intervals.

For example:

  • You have a page showing all recipes, and new recipes are added every hour or so.
  • By setting revalidate to 3600 seconds (1 hour), you ensure that users always see an updated list of recipes without needing to rebuild the entire page manually.

Handling Cache and Data Freshness with Revalidate

When using revalidate, Next.js ensures that the page is cached between revalidation periods, but the cache is refreshed after the defined interval. This helps maintain a balance between performance (loading static content quickly) and data freshness (updating content periodically).

  • The page is cached in the CDN or server after the first request.
  • When the revalidate time expires, the next user request triggers a server-side regeneration of the page.
  • Once the page is regenerated, it’s cached again until the next revalidation cycle.

Example: If you set revalidate: 3600, the page will serve the cached version for 1 hour, after which the first new visitor will trigger the re-fetch of the latest recipes.


Performance Benefits of Revalidate

Revalidate gives you the best of both worlds: fast, static content and dynamically updated data. Instead of waiting for a full rebuild, you get to update your pages at runtime based on real-world usage.

Why It’s Valuable:

  • Static Performance: Pages are served quickly from cache while still being updated in the background.
  • Flexible Updates: You can control how often each page should be updated by setting different revalidation intervals for different parts of your app.

Summary

In this tutorial, you learned how to set up and use revalidate in Next.js 14 App Router. By using revalidation, you can keep static pages fresh without sacrificing performance. This technique is ideal for pages that don’t need real-time updates but require periodic content refreshes.

Key Takeaways:

  • Revalidate allows you to refresh static pages based on a time interval.
  • It’s perfect for scenarios like recipe listings, where the content updates periodically but doesn’t need to be real-time.
  • Revalidate strikes a balance between fast static pages and fresh, dynamic content.

In the next tutorial, we’ll explore Incremental Static Regeneration (ISR), which builds on the concept of revalidate and allows more flexible, dynamic page generation.

Next.js
Clap here if you liked the blog