Revalidation

Master Next.js revalidation — time-based, on-demand, and tag-based strategies for keeping cached content fresh without sacrificing performance.

Last reviewed: January 2025

·Next.js 13Next.js 14Next.js 15
✅
Quick Understanding: Revalidation tells Next.js when to regenerate a cached page or data. Time-based revalidation rebuilds after N seconds. On-demand revalidation rebuilds immediately when you call revalidatePath() or revalidateTag() — typically from a CMS webhook.

🔍 What Is It?

Revalidation is the mechanism for invalidating and refreshing cached content in Next.js. Three strategies:

  1. Time-based — next: { revalidate: 3600 } — refresh after N seconds (ISR)
  2. On-demand path — revalidatePath('/products/slug') — invalidate a specific URL
  3. On-demand tag — revalidateTag('products') — invalidate all content with a tag

Revalidation uses stale-while-revalidate: serve the cached version immediately, rebuild in the background, serve fresh version to subsequent requests.

🎯 Why Do We Need It?

Without revalidation, you face a binary choice:

  • →SSG — fast but stale until next full deploy
  • →SSR — always fresh but slow and expensive

Revalidation gives you a third option: static performance + controlled freshness. You decide exactly when content updates, either by time or by event (CMS publish, price change, stock update).

🏗️ What Happens in Real Projects?

Revalidation strategy by content type:

Content TypeStrategyRevalidate
Homepage heroOn-demandCMS publish webhook
Product pagesTime + On-demand1hr + price change webhook
Blog postsOn-demandCMS publish webhook
NavigationOn-demandCMS publish webhook
Exchange ratesTime-based5 minutes
Static pagesNeverDeploy only

⚙️ How It Works

On-demand revalidation flow:

  1. Editor publishes a blog post in CMS
  2. CMS sends POST to /api/revalidate with { type: 'post', slug: 'my-post' }
  3. Route Handler verifies webhook secret
  4. Calls revalidateTag('posts') and revalidatePath('/blog/my-post')
  5. Next.js marks those cache entries as stale
  6. Next request to /blog/my-post triggers a background rebuild
  7. Fresh HTML served to subsequent requests

💻 Example

Complete Revalidation Setup — A production-ready revalidation webhook with tag-based invalidation.

ts
// lib/data/posts.ts
export async function getPost(slug: string) {
  const res = await fetch(
    `https://cms.example.com/posts/${slug}`,
    {
      next: {
        revalidate: 86400, // 24hr safety net
        tags: [
          'posts',           // All posts
          `post-${slug}`,  // This specific post
        ],
      },
    }
  );
  return res.json();
}

export async function getNavigation() {
  const res = await fetch('https://cms.example.com/navigation', {
    next: { revalidate: 3600, tags: ['navigation'] },
  });
  return res.json();
}

🤔 Common Confusions

❓ What is the difference between revalidatePath and revalidateTag?

revalidatePath invalidates a specific URL. revalidateTag invalidates all cache entries that used fetch() with that tag. Tags are more powerful — a single CMS publish can revalidate the post page, the blog listing, and the homepage (all tagged with "posts") with one revalidateTag("posts") call.

❓ Does revalidation happen immediately?

revalidatePath and revalidateTag mark cache entries as stale immediately. The actual rebuild happens on the NEXT request to that path. So the current request sees stale data, and the next user gets fresh data. This is stale-while-revalidate behaviour.

❓ Can I call revalidatePath from a Client Component?

No — revalidatePath and revalidateTag are server-only functions. Call them from Server Actions or Route Handlers. A Client Component can trigger a Server Action that calls revalidatePath, or POST to a Route Handler that calls it.

🚨 Common Production Issues

Revalidation not working on self-hosted setups — revalidatePath/revalidateTag work per-server-instance. If you have multiple server instances, only the instance that received the webhook revalidates. Use a shared cache store (Redis) with the Next.js cache handler for multi-instance setups.

Missing the leading slash in revalidatePath — revalidatePath("products/slug") without a leading slash does not work. Always use revalidatePath("/products/slug").

Over-invalidating with broad tags — revalidateTag("all") on a large site triggers rebuilds of thousands of pages simultaneously, causing a server spike. Use specific tags and invalidate only what changed.

✅ Best Practices

Tag every fetch call with at least one meaningful tag — enables precise on-demand invalidation

Use hierarchical tags: ["posts", "post-slug"] — revalidate all or specific

Always verify webhook secrets — an unprotected revalidation endpoint is a DoS vector

Combine time-based (safety net) with on-demand (immediate) revalidation

Log all revalidation events with timestamps for debugging stale content reports

🏛️ Architect's Note

Senior Architect's Perspective

Design your tag taxonomy before writing any fetch calls. A consistent tagging strategy — e.g., ["entity-type", "entity-type-id"] — makes on-demand revalidation predictable and maintainable. Document it in your team's architecture decision records (ADRs).

💬 Frequently Asked Questions

How do I revalidate a page from a Server Action?

Call revalidatePath() or revalidateTag() directly inside the Server Action before returning. Example: async function updateProduct(data) { "use server"; await db.product.update({...}); revalidatePath("/products/" + data.slug); }

What happens if revalidation fails (the data source is down)?

The stale cached content continues to be served. Next.js does not replace the cache with an error state. This is actually desirable — users see stale but valid content rather than an error page. The cache acts as a resilience layer.

Can I revalidate from outside the Next.js app?

Yes — create a Route Handler endpoint and call it from anywhere (CI/CD pipeline, CMS, external service). This is the standard pattern for CMS-driven sites: CMS publishes → webhook fires → Route Handler calls revalidateTag.

🎯 Key Takeaways

1Three revalidation strategies: time-based (revalidate: N), path-based, and tag-based
2revalidateTag is more powerful than revalidatePath — one call can refresh many pages
3Tag every fetch call with meaningful tags for precise on-demand invalidation
4Revalidation marks cache as stale — the rebuild happens on the next request
5Always verify webhook secrets — unprotected endpoints are a DoS risk
6Stale-while-revalidate: users always get fast cached content, never wait for rebuilds

🎯 Practice this topic in interviews

↗ Where this topic fits

Sources

Sources / References

Use these Next.js references to verify the concept in official docs and continue into the most relevant SplashRide pages.

Related SplashRide pages

SplashRide Next.js learning path

Browse the full Next.js topic collection and learning order on SplashRide.

Next.js Interview Prep

Practice Next.js interview questions and scenario-based answers.

Frontend Engineer Career Path

A beginner-friendly journey through web foundations, React, production frontend engineering, and interview preparation.

Full Stack Java Developer Career Path

A guided route through frontend foundations, Java backend engineering, delivery workflows, and interview readiness.

Incremental Static Regeneration (ISR)

Master ISR — the Next.js feature that gives you static performance with dynamic freshness. Learn time-based and on-demand revalidation for real production systems.

Caching Strategies

Master advanced caching strategies in Next.js — combining SSG, ISR, SSR, and client caching for optimal performance across different content types.