Next.js’s caching and revalidation system has evolved significantly with the App Router (Next.js 13/14). While the Pages Router relied on getStaticProps and revalidate, the App Router introduces a new, powerful caching model centered around the fetch API, server actions, and on-demand cache invalidation functions.
This guide explains how to properly revalidate cache in both the App Router and the legacy Pages Router, covering time-based and on-demand approaches.
Understanding Cache Revalidation in Next.js
Revalidation ensures your statically rendered content stays fresh while maintaining fast load times. In Next.js, it works by regenerating data or pages when specific conditions are met.
In Summary:
- Pages Router: Uses
getStaticPropswithrevalidateorres.revalidate(). - App Router: Uses
fetch(..., { next: { revalidate } }),revalidatePath(), andrevalidateTag().
App Router Cache Revalidation (Next.js 13/14)
The App Router introduced a new caching architecture with three layers:
- Request Memoization – Prevents duplicate fetch calls within the same request lifecycle.
- Data Cache – Stores fetched data responses across requests.
- Full Route Cache – Caches the rendered output of routes (HTML + React tree).
These layers work together to provide a flexible, high-performance caching model.
1. Time-Based Revalidation in App Router
Time-based revalidation in the App Router is configured directly inside the fetch() call.
Example:
// app/posts/page.js
export default async function PostsPage() {
const res = await fetch('https://api.example.com/posts', {
next: { revalidate: 60 }, // Revalidate every 60 seconds
});
const posts = await res.json();
return (
<div>
<h1>Latest Posts</h1>
<ul>
{posts.map(post => <li key={post.id}>{post.title}</li>)}
</ul>
</div>
);
}
How it works:
- The page is statically rendered and cached.
- After 60 seconds, the next request triggers a background revalidation.
- The updated data replaces the old cache seamlessly.
Note: There’s no getStaticProps or getServerSideProps in the App Router—all data fetching happens via fetch() or server actions.
2. On-Demand Revalidation in App Router
Next.js now offers two new functions for manual cache revalidation:
revalidatePath(path)— Revalidates a specific route path.revalidateTag(tag)— Revalidates all fetches associated with a tag.
You can call these from Route Handlers or Server Actions.
Example: Using revalidatePath()
// app/api/revalidate/route.js
import { revalidatePath } from 'next/cache';
export async function POST(req) {
const { path } = await req.json();
revalidatePath(path); // Invalidate and re-generate this route
return Response.json({ revalidated: true, path });
}
Example: Using revalidateTag()
You can tag your fetches to group them logically:
// app/products/page.js
export default async function ProductsPage() {
const res = await fetch('https://api.example.com/products', {
next: { tags: ['products'] },
});
const products = await res.json();
return <ProductList data={products} />;
}
// app/actions/revalidateProducts.js
'use server';
import { revalidateTag } from 'next/cache';
export async function revalidateProducts() {
revalidateTag('products'); // Revalidate all fetches with 'products' tag
}
You can trigger revalidateProducts() from CMS webhooks or admin dashboards.
Comparing Caching Mechanisms in the App Router
| Cache Type | Description | Lifecycle | Example |
|---|---|---|---|
| Request Memoization | Deduplicates fetch calls during the same render | Request-level | Same fetch() inside one render won’t re-run |
| Data Cache | Stores fetch responses between requests | Time-based or manual revalidation | Controlled via revalidate or tags |
| Full Route Cache | Stores the fully rendered route | Cleared on route revalidation | Affected by revalidatePath() |
Together, these layers optimize performance and give developers full control over how and when data stays fresh.
Pages Router Revalidation (Legacy)
If you’re still using the Pages Router, you’ll continue to use getStaticProps and API routes for cache revalidation.
Time-Based Example
export async function getStaticProps() {
const res = await fetch('https://api.example.com/posts');
const posts = await res.json();
return {
props: { posts },
revalidate: 60,
};
}
On-Demand Example
export default async function handler(req, res) {
try {
await res.revalidate('/blog/my-post');
return res.json({ revalidated: true });
} catch (err) {
return res.status(500).json({ message: 'Error revalidating' });
}
}
Best Practices for Cache Revalidation
- Use
fetchoptions wisely — Add{ next: { revalidate, tags } }for precise control. - Tag related data sources — Makes revalidation scalable via
revalidateTag(). - Secure on-demand endpoints with tokens or auth checks.
- Avoid redundant fetches — Rely on Next.js’s built-in memoization.
- Combine methods — Use time-based revalidation for regular updates and manual revalidation for instant updates.
Conclusion
Revalidation in Next.js has become more modular, declarative, and powerful with the App Router. You can now manage freshness at both the data-fetch and route-render levels using built-in functions.
Quick Summary
| Router Type | Method | API | Ideal Use |
|---|---|---|---|
| App Router | Time-Based | fetch(..., { next: { revalidate } }) | Periodic data refresh |
| App Router | On-Demand | revalidatePath(), revalidateTag() | Real-time updates |
| Pages Router | Time-Based | getStaticProps + revalidate | Static ISR sites |
| Pages Router | On-Demand | res.revalidate() | Manual cache invalidation |
With these tools, you can confidently manage caching and revalidation in any Next.js version — ensuring both speed and freshness across your app.
Next Steps:
- Explore Next.js App Router Caching Docs
- Implement
revalidateTag()in your CMS webhooks - Use tagged fetches for efficient selective cache invalidation
