Mahamudul Hasan Rubel
HomeAboutProjectsSkillsExperienceBlogPhotosContact
Mahamudul Hasan Rubel

Senior Software Engineer crafting high-performance web applications and SaaS platforms.

Navigation

  • Home
  • About
  • Projects
  • Skills
  • Experience
  • Blog
  • Photos
  • Contact

Get in Touch

Available for senior/lead roles and consulting.

bd.mhrubel@gmail.comHire Me

© 2026 Mahamudul Hasan Rubel. All rights reserved.

Built with using Next.js 16 & Tailwind v4

Back to Blog
Next.jsReactJune 20, 20264 min read

Caching and revalidation in the Next.js App Router: A Practical Guide

Caching and revalidation in the Next.js App Router are often misunderstood. Learn how to control the Data Cache and keep your production data fresh today.

Next.jsReactWeb PerformanceCachingApp RouterFrontendTypeScript
Detailed view of a network switch featuring multiple ethernet ports and LED indicators.

When we first migrated our legacy dashboard to the Next.js App Router, we assumed the default caching behavior would just "work." It didn't. We spent two days debugging why our users were seeing stale admin settings after updates, only to realize we hadn't properly configured our revalidation logic.

Understanding the Data Cache

The Next.js App Router uses a sophisticated, multi-layered caching system. At its core is the Data Cache, a persistent HTTP cache that stores the results of fetch requests across server requests and deployments. By default, Next.js caches these requests indefinitely. If you’re building a static blog, this is a feature; if you’re building a SaaS platform, it’s a silent bug waiting to happen.

When you use fetch in a Server Component, Next.js automatically memoizes the result. If you call the same endpoint twice in one render tree, the second call hits the cache. This is great for performance, but it’s easy to trip over if you don't understand server components vs client components: a practical guide.

The wrong turn: Global revalidation

We initially tried using the revalidate segment config at the route level:

JAVASCRIPT
// page.tsx
export const revalidate = 60; // Revalidate every 60 seconds

This seemed efficient, but it caused "cache thrashing." We were revalidating data that hadn't changed, consuming unnecessary database cycles and increasing latency by about 120ms per request. We were optimizing for convenience, not for our actual data lifecycle.

Implementing tag-based revalidation

The real power lies in tag-based revalidation. Instead of relying on time-based intervals, you attach tags to your fetch requests and invalidate them only when the underlying data changes.

Here is how we implemented it in our API layer:

JAVASCRIPT
// lib/api.ts
export async function getDashboardStats() {
  const res = await fetch(CE9178">'https://api.example.com/stats', {
    next: { tags: [CE9178">'dashboard-stats'] }
  });
  return res.json();
}

When an admin updates a record, we trigger the revalidation manually from a Server Action or an API route:

JAVASCRIPT
import { revalidateTag } from CE9178">'next/cache';

export async function updateStats() {
  // ... perform database update
  revalidateTag(CE9178">'dashboard-stats');
}

This approach is surgically precise. We only bust the cache when it’s actually stale, ensuring our users see the latest data immediately after a mutation. It’s a massive upgrade from time-based polling and keeps our infrastructure costs lower by reducing redundant server-side compute.

Dealing with dynamic data

Sometimes, you need to opt out of caching entirely. If your page relies on user-specific session data or highly volatile information, don't force it into the cache.

You can bypass the Data Cache by setting the cache option in fetch:

JAVASCRIPT
const data = await fetch(CE9178">'https://api.example.com/live-price', {
  cache: CE9178">'no-store'
});

Using no-store is the nuclear option. It tells Next.js to ignore the cache entirely and fetch fresh data on every single request. Use this sparingly. In my experience, if you find yourself using no-store on every page, you might need to rethink your data architecture. Check out react props and state: where your data should live to see if some of this state actually belongs on the client side instead of the server.

FAQ: Common caching hurdles

Q: Does revalidatePath replace revalidateTag? A: Not exactly. revalidatePath targets all cache entries associated with a specific route segment, while revalidateTag is more granular. Use revalidateTag when you have multiple components on a page that depend on the same underlying data source.

Q: Why is my cache not revalidating in development? A: Next.js caching behavior differs slightly between next dev and next build. In development, fetch requests are generally not cached by default to make debugging easier. Always test your revalidation logic in a production-like environment (e.g., next build && next start).

Q: How do I clear the cache for everything? A: You can’t easily wipe the entire Data Cache programmatically in the App Router. If you find yourself needing to do this, you likely have a design flaw in your revalidation strategy. Stick to granular tags.

Final thoughts

Caching and revalidation in the Next.js App Router is a game of managing trade-offs. I’m still experimenting with how to integrate this with external caching layers like Redis—sometimes the built-in Data Cache feels a bit like a black box. If you’re just starting, keep it simple. Use tags, avoid no-store unless necessary, and keep your data dependencies explicit. Don't over-engineer the cache until you’ve measured the impact on your user experience.

Back to Blog

Similar Posts

Close-up of JavaScript code on a laptop screen, showcasing programming in progress.
ReactNext.jsJune 20, 20264 min read

Profiling and fixing a slow React render: A Practical Guide

Profiling and fixing a slow React render is easier when you stop guessing. Learn how to use React DevTools to find bottlenecks and optimize your app.

Read more
A close-up view of a laptop displaying a search engine page.
Next.jsReactJune 20, 20264 min read

Streaming and Suspense in Next.js: Optimize Your Page Load

Master streaming and Suspense in Next.js to drastically improve perceived performance. Learn how to stream UI components for a faster, responsive experience.

Read more
An artistic arrangement of golden gears on a dark backdrop, symbolizing mechanics and cooperation.
ReactNext.jsJune 20, 20264 min read

Component architecture that survives a growing team in Next.js

Component architecture that survives a growing team requires strict boundaries. Learn how we scaled our React/Next.js codebase to keep features moving fast.

Read more