DEV Community

Cover image for How to Implement Revalidation in Next.js for Fresh Data Without Performance Loss
Melvin Prince
Melvin Prince

Posted on

3 1 1 1 1

How to Implement Revalidation in Next.js for Fresh Data Without Performance Loss

In our previous post, we explored the differences between static caching and dynamic caching in Next.js, understanding when to use each strategy for optimal performance. But what if you want the best of both worlds? What if you need the speed of static pages while still ensuring your content stays up-to-date without forcing a full site rebuild?

This is where Incremental Static Regeneration (ISR) comes in. ISR is a game-changer because it allows you to rebuild static pages in the background without affecting the user experience. It provides the perfect middle ground—fast-loading pages that can still update periodically without requiring a redeployment.

In this post, we’ll dive deep into:

How ISR works and when to use it

How to implement revalidate in getStaticProps

Best practices for choosing the right revalidation time

Advanced techniques like manual and conditional revalidation

By the end of this post, you’ll have a clear understanding of how to use ISR effectively to ensure fresh data without sacrificing performance. Let’s get started!

Understanding Incremental Static Regeneration (ISR)

What is ISR?

Incremental Static Regeneration (ISR) is a feature in Next.js that allows static pages to be updated without requiring a full site rebuild. Traditionally, static site generation (SSG) creates all pages at build time, which makes them incredibly fast but also means they remain unchanged until the next deployment. ISR solves this limitation by enabling Next.js to regenerate static pages in the background while keeping the website operational.

With ISR, you can define a revalidation period that tells Next.js when to refresh the page. If a request comes in after this period has elapsed, the page will be rebuilt in the background, ensuring that users always get fresh content while maintaining the benefits of static generation.

How ISR Works Behind the Scenes

When a page uses ISR, the process follows these steps:

  1. Initial Build: The page is generated as a static file at build time and served to users.
  2. Serving Cached Page: Until the revalidation time expires, users continue to see the cached version of the page.
  3. Triggering Regeneration: When a request comes in after the revalidation period has expired, Next.js starts regenerating the page in the background while still serving the old version.
  4. Replacing the Old Page: Once the regeneration is complete, the newly generated page replaces the old version, and all subsequent users get the updated content.

This approach ensures that pages are always available instantly, even while they are being updated in the background, making ISR an excellent choice for pages that need periodic updates but don’t require real-time data.

When Should You Use ISR?

ISR is ideal in scenarios where content updates frequently but does not require real-time updates on every request. Some common use cases include:

  • News websites that publish articles and want to update content periodically without slowing down page loads.
  • E-commerce product pages where product details change but don’t need instant updates.
  • Blog posts that need occasional updates while keeping fast static performance.
  • Marketing pages with information that changes on a schedule, such as event pages or sales promotions.

ISR helps maintain the speed advantages of static pages while allowing for automatic updates, eliminating the need for frequent manual deployments.

How revalidate Works in getStaticProps

Now that we understand what ISR is and when to use it, let’s dive into how it works in practice. The key to implementing ISR in Next.js is the revalidate property inside getStaticProps.

Using revalidate in getStaticProps

In Next.js, getStaticProps is used to fetch data at build time and generate a static page. By adding a revalidate field to its return object, we tell Next.js to regenerate the page at a specified interval after a request is made.

Here’s an example of how revalidate works:

export async function getStaticProps() {
  const res = await fetch('https://api.example.com/data');
  const data = await res.json();

  return {
    props: { data },
    revalidate: 60, // Revalidates the page every 60 seconds
  };
}
Enter fullscreen mode Exit fullscreen mode

What Happens Behind the Scenes?

  1. The page is built at deployment time with the initial data.
  2. Subsequent requests within 60 seconds receive the same cached page.
  3. After 60 seconds, the next request triggers a background regeneration.
  4. During the regeneration, the old page is still served until the new one is ready.
  5. Once the regeneration completes, the new version replaces the old one.

This process ensures that users always get a fast-loading page, while the content remains reasonably fresh without requiring frequent server requests.

Example Use Case: Revalidating Blog Posts Every 5 Minutes

Imagine you’re running a blog where new articles get published, but updates to existing ones happen periodically. You want to refresh the data every five minutes without switching to server-side rendering. Here’s how you’d implement it:

export async function getStaticProps() {
  const res = await fetch('https://api.example.com/posts');
  const posts = await res.json();

  return {
    props: { posts },
    revalidate: 300, // Revalidates every 300 seconds (5 minutes)
  };
}
Enter fullscreen mode Exit fullscreen mode

How Does This Improve Performance?

  • Users get a pre-rendered static page for a super-fast experience.
  • The blog updates without requiring a manual rebuild or deployment.
  • API requests are minimized because data is fetched only when necessary.

When to Use ISR vs. SSR vs. Static Generation: Practical Guidelines

Incremental Static Regeneration (ISR) is powerful, but knowing exactly when and how to use it in your project can make a huge difference in your site's performance and user experience. In this section, we'll clearly differentiate between ISR, Server-Side Rendering (SSR), and fully static pages (SSG) by looking at specific scenarios, helping you make informed decisions.

ISR (Incremental Static Regeneration)

Use ISR when:

  • Your content changes frequently but not constantly.
  • You need fast-loading pages but also want them regularly refreshed without manual intervention.
  • Slightly stale data (minutes or hours) is acceptable.

Example Scenarios:

  • News or blog sites updating content several times a day.
  • E-commerce sites showcasing product listings updated hourly.

Implementation Example:

export async function getStaticProps() {
  const res = await fetch('https://api.example.com/products');
  const products = await res.json();

  return {
    props: { products },
    revalidate: 3600, // Updates once every hour
  };
}
Enter fullscreen mode Exit fullscreen mode

When to Use Server-Side Rendering (SSR)?

SSR (getServerSideProps) generates the page on each request, providing always up-to-date data at the expense of performance.

When SSR Makes Sense:

  • Data must be fresh every single request.
  • Real-time dashboards, stock prices, user-specific data.

SSR Example:

export async function getServerSideProps(context) {
  const res = await fetch(`https://api.example.com/user/${context.params.id}`);
  const userData = await res.json();

  return { props: { user: userData } };
}
Enter fullscreen mode Exit fullscreen mode

When to Stick with Static (SSG)

Static pages built entirely at build time offer the best performance because they never require regeneration after deployment.

Ideal Use Cases for Static Pages:

  • Marketing or landing pages with infrequent updates.
  • Documentation websites with relatively static content.

Static Generation Example:

export async function getStaticProps() {
  const res = await fetch('https://api.example.com/static-info');
  const staticInfo = await res.json();

  return { props: { staticInfo: staticInfo } };
}
Enter fullscreen mode Exit fullscreen mode

Quick Comparison Table

Feature ISR SSR Static (SSG)
Rendering At build & periodic revalidation On every request Only at build time
Data Freshness Frequent, but slightly delayed Always fresh Stale after deployment
Performance High Moderate Very High
Server Load Low High Minimal

Understanding these distinctions will enable you to apply ISR precisely where it's most beneficial, improving both your user experience and your infrastructure efficiency.

Advanced Techniques: Manual and Conditional Revalidation

While automatic revalidation with getStaticProps is powerful, sometimes you need more control over exactly when and how pages regenerate. Next.js provides advanced techniques to manually trigger regeneration or conditionally revalidate only when necessary.

Manual Revalidation with res.revalidate()

Next.js allows you to manually trigger revalidation through a simple API call. This is extremely useful for scenarios where you want immediate updates when content changes—such as when an admin publishes or edits content in your CMS.

Implementing Manual Revalidation:

Create a dedicated API route to manually trigger regeneration:

// pages/api/revalidate.js
export default async function handler(req, res) {
  if (req.query.secret !== process.env.REVALIDATION_SECRET) {
    return res.status(401).json({ message: 'Invalid token' });
  }

  try {
    await res.revalidate('/blog');
    return res.json({ message: 'Blog page revalidated successfully' });
  } catch (error) {
    return res.status(500).json({ message: 'Error revalidating page' });
  }
}
Enter fullscreen mode Exit fullscreen mode

When to Use Manual Revalidation?

  • Instantly updating content after a CMS update.
  • Immediately reflecting important changes, like price updates or breaking news.
  • Reducing unnecessary regeneration by triggering updates only when content actually changes.

Conditional Revalidation

Conditional revalidation is useful when you want to regenerate a page only if the data has changed, thereby minimizing server load and API calls.

Example of Conditional Revalidation:

Here's how you could conditionally revalidate a page based on whether new data is available:

export async function getStaticProps() {
  const res = await fetch('https://api.example.com/data');
  const data = await res.json();

  const dataHash = generateHash(data); // Your function to hash data
  const previousHash = getCachedHash(); // Retrieve from Redis or database

  if (dataHash === previousHash) {
    // Skip regeneration since data is unchanged
    return {
      props: { data },
      revalidate: 600, // Try again later
    };
  }

  // Update cached hash since data changed
  updateCachedHash(dataHash);

  return {
    props: { data },
    revalidate: 60,
  };
}
Enter fullscreen mode Exit fullscreen mode

How This Improves Your Application:

  • Reduces unnecessary regenerations, saving resources.
  • Ensures pages only regenerate when relevant, new data appears.
  • Helps scale your application efficiently, especially under high traffic.

Best Practices for Advanced Revalidation:

  • Secure your manual revalidation endpoint with a secret token to avoid unauthorized revalidation.
  • Monitor performance and logs to optimize your revalidation intervals.
  • Keep conditional revalidation logic lightweight—complex checks can slow down regeneration and diminish performance advantages.

With these advanced techniques, you'll gain greater control, efficiency, and performance optimization beyond the basics provided by automatic ISR.

Best Practices for Optimizing ISR in Next.js

Incremental Static Regeneration is a robust feature, but like any powerful tool, it requires thoughtful consideration to truly maximize its potential. In this section, we'll explore practical strategies and best practices to fine-tune ISR effectively, striking the ideal balance between fresh data and performance efficiency.


1. Choose the Optimal Revalidation Time

Selecting an appropriate revalidate interval is crucial. If the interval is too short, you risk excessive regeneration, increasing API and server load. If it’s too long, your users could see outdated content. Aim to strike a balance based on your application's use case.

Example guidelines:

  • High frequency (1-10 mins): For blogs, news, weather updates.
  • Moderate frequency (30 mins - 1 hour): For product listings, reviews, or dynamic home pages.
  • Low frequency (multiple hours or days): Static documentation, infrequently updated landing pages.

Limit Regeneration with Cache-Control Headers

Next.js allows you to specify caching headers explicitly, further controlling caching at the CDN or browser level. This complements ISR and helps reduce unnecessary load.

Example of setting Cache-Control headers:

// pages/api/products.js
export default async function handler(req, res) {
  const products = await fetchProductsFromDB();
  res.setHeader('Cache-Control', 'public, s-maxage=3600, stale-while-revalidate=59');
  res.status(200).json(products);
}
Enter fullscreen mode Exit fullscreen mode
  • s-maxage: Sets the cache duration on CDN level.
  • stale-while-revalidate: Allows serving stale content temporarily while the data updates in the background.

2. Avoiding Excessive Regenerations with Conditional Checks

Conditional regeneration reduces unnecessary rebuilds. Implement a check to verify if the data has changed before regenerating the page, conserving server resources and improving scalability.

Example scenario:

export async function getStaticProps() {
  const newData = await fetch('https://api.example.com/data').then(res => res.json());
  const cachedDataHash = getCachedHash(); // from Redis/cache
  const newDataHash = hashFunction(newData);

  if (cachedHash === newData.hash) {
    // Skip regeneration as data hasn’t changed
    return {
      props: { data: newData },
      revalidate: false,
    };
  }

  // Data has changed
  return {
    props: { data: newData },
    revalidate: 60,
  };
}
Enter fullscreen mode Exit fullscreen mode

This approach ensures regeneration happens only when necessary.


Leveraging Manual Revalidation Wisely

Manual revalidation offers precise control, but it can introduce complexity. Use it strategically:

  • Immediately updating critical pages after content edits (CMS integration).
  • Responding quickly to breaking news or urgent product updates.
  • Balancing manual triggers with scheduled ISR to ensure data consistency without overwhelming resources.

Monitoring and Fine-Tuning ISR in Production

Observing ISR performance after deployment helps fine-tune your revalidation strategies:

  • Track regeneration frequency and duration.
  • Monitor API response times and cache hit ratios.
  • Adjust the revalidate period based on real-world usage.

Popular monitoring tools:

  • Vercel Analytics: Provides built-in insights into page regeneration performance.
  • Datadog or New Relic: Advanced application monitoring and logging for custom setups.

Summary of Best Practices

  • Carefully select your revalidation interval to match content freshness needs.
  • Use manual revalidation to immediately refresh critical content updates.
  • Implement conditional revalidation to avoid unnecessary regenerations.
  • Continuously monitor and refine your revalidation strategy based on production metrics.

Following these best practices ensures your Next.js applications benefit fully from ISR, balancing speed and freshness without sacrificing performance.

Conclusion

In this post, we've thoroughly explored how Incremental Static Regeneration (ISR) lets you achieve fresh data without compromising performance in Next.js applications. We've seen that ISR bridges the gap between static pages' unbeatable performance and dynamic content's need for freshness.

To recap, we covered:

  • What ISR is and when to use it—offering static pages with periodic updates.
  • How to use the revalidate option in getStaticProps effectively.
  • Advanced techniques like manual and conditional revalidation for fine-grained control.
  • Practical best practices for optimizing ISR to balance freshness and speed, including conditional regeneration, manual revalidation, and performance monitoring.

By mastering ISR, you'll be able to build Next.js apps that deliver lightning-fast user experiences without compromising on the freshness of your content.

What's Next?

In the next post, we'll dive into API caching in Next.js, learning how to further enhance performance with middleware and custom caching headers.

Be sure to check out the previous posts to strengthen your foundation:

For more content, visit my portfolio at melvinprince.io or connect with me on LinkedIn. Stay tuned!

Hostinger image

Get n8n VPS hosting 3x cheaper than a cloud solution

Get fast, easy, secure n8n VPS hosting from $4.99/mo at Hostinger. Automate any workflow using a pre-installed n8n application and no-code customization.

Start now

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay