Next.js Caching Explained: Request Cache, Data Cache and Full Route Cache
Caching concepts have surfaced repeatedly throughout this course — fetch's cache option in Lesson 2.5, revalidatePath and revalidateTag in Lesson 2.4 — but always in the context of one specific layer. Next.js actually maintains four distinct caching layers working together, and understanding all four, and specifically how they relate to each other, resolves a lot of confusion developers commonly hit when a page 'isn't updating' despite a data change.
This lesson maps out all four layers precisely: Request Memoization (the shortest-lived, per-render layer from Lesson 2.5), the Data Cache (fetch's persistent, cross-request cache), the Full Route Cache (caching an entire rendered route's output), and the Router Cache (a client-side cache of visited routes for instant back/forward navigation) — and clarifies exactly which revalidation tool clears which layer.
Learning Objectives
- Name and distinguish all four of Next.js's distinct caching layers.
- Understand the scope and lifetime of each caching layer.
- Determine which revalidation function (revalidatePath, revalidateTag, router.refresh) clears which layer.
- Diagnose why a page might show stale data despite an apparently successful data update.
- Apply the appropriate caching strategy deliberately rather than being surprised by default behavior.
Core Definitions
- Request Memoization: The shortest-lived cache layer, deduplicating identical fetch calls made within a single render pass, cleared automatically once that render completes.
- Data Cache: A persistent, server-side cache of fetch() results that can survive across multiple separate requests and deployments, controlled by the cache and next.revalidate fetch options.
- Full Route Cache: A cache of an entire route's rendered output (HTML and the React Server Component payload), generated at build time for static routes and served without re-rendering on matching requests.
- Router Cache (Client-side Cache): A client-side, in-memory cache of previously visited route segments, enabling instant navigation when revisiting them without a fresh server request.
- Cache invalidation: The process of marking cached data or a cached route as stale so it will be regenerated, triggered by functions like revalidatePath, revalidateTag, or router.refresh().
Detailed Explanation
The first, shortest-lived layer is Request Memoization, covered in Lesson 2.5: within a single render pass for one specific request, if multiple components call fetch() with identical arguments, Next.js executes the underlying network request only once and shares the result. This cache exists only for the duration of that single render and is automatically cleared once it completes — it has no bearing on whether a later, separate request sees fresh or stale data.
The second layer, the Data Cache, is what most of Lesson 2.5's discussion of cache: 'force-cache' versus 'no-store' versus next.revalidate actually controls. Unlike Request Memoization, the Data Cache persists across multiple separate requests, and even across deployments if the underlying data and fetch configuration haven't changed — it's specifically what makes Static Site Generation and ISR possible, by avoiding the need to re-fetch the same data on every single request.
The third layer, the Full Route Cache, operates one level above individual fetch calls: it caches an entire route's rendered output — both the HTML sent to the browser and the React Server Component payload used for client-side navigation — generated once at build time for statically rendered routes. This is what allows a static page to be served instantly without any server-side rendering work happening again on a matching request; it's closely tied to, but distinct from, the Data Cache, since a route can only be part of the Full Route Cache if all of its underlying data is itself cacheable (no dynamic API usage, no no-store fetches, as covered in Lesson 2.3's discussion of what triggers dynamic rendering).
The fourth and final layer, the Router Cache (sometimes called the Client-side Router Cache), is unique in that it lives entirely in the visitor's browser rather than on the server: as a user navigates between pages using the Link component (Lesson 1.8), Next.js caches the visited route segments' React Server Component payloads client-side, enabling genuinely instant navigation when a user returns to a previously visited page (like clicking the browser's back button) without needing a fresh server round-trip at all.
Understanding which revalidation mechanism affects which layer is the key to resolving 'my data isn't updating' confusion: revalidatePath and revalidateTag (Lesson 2.4) invalidate both the Data Cache and the Full Route Cache for the affected path or tag, causing regeneration on the next request — but they do NOT automatically clear an individual visitor's client-side Router Cache for a page they've already visited in their current browsing session. This is why, occasionally, a developer correctly calls revalidatePath after a mutation, confirms fresh data is being served to new visitors, yet a specific browser tab that had already visited that page beforehand continues showing the old, client-cached version until a hard refresh or explicit router.refresh() call clears that browser's own Router Cache specifically.
Next.js's Four Caching Layers, from Shortest to Longest-Lived
{"heading":"Next.js's Four Caching Layers, from Shortest to Longest-Lived","description":"Visualize all four caching layers and their scope:\n\n1. REQUEST MEMOIZATION (shortest-lived)\n Scope: ONE render pass, ONE request. Cleared automatically after that render.\n\n2. DATA CACHE (server-side, persistent)\n Scope: Across MANY requests, even across deployments. Controlled by fetch's cache/revalidate options.\n\n3. FULL ROUTE CACHE (server-side, persistent)\n Scope: An entire route's rendered HTML + RSC payload, generated at build time for static routes.\n\n4. ROUTER CACHE (client-side, in the browser)\n Scope: ONE visitor's browser session, caching visited route segments for instant back/forward navigation.\n\nrevalidatePath/revalidateTag --> clears layers 2 & 3 (server-side)\nrouter.refresh() / hard reload --> clears layer 4 (that browser's own client-side cache)"}
Next.js Practical Example
// app/actions/updatePrice.ts — a mutation touching multiple cache layers
'use server';
import { revalidatePath, revalidateTag } from 'next/cache';
import { prisma } from '@/lib/prisma';
export async function updatePrice(productId: string, newPrice: number) {
await prisma.product.update({
where: { id: productId },
data: { price: newPrice },
});
// Clears the Data Cache for anything tagged 'products'
revalidateTag('products');
// Clears the Full Route Cache for this specific static page
revalidatePath(`/products/${productId}`);
// NOTE: this does NOT clear an already-open browser tab's Router Cache —
// that visitor would need router.refresh() or a hard reload to see the change
// if they already have that page cached client-side from an earlier visit.
}
// components/RefreshButton.tsx — manually clearing the CLIENT-side Router Cache
'use client';
import { useRouter } from 'next/navigation';
export default function RefreshButton() {
const router = useRouter();
return <button onClick={() => router.refresh()}>Refresh</button>;
}
updatePrice correctly clears both the Data Cache (via revalidateTag) and the Full Route Cache (via revalidatePath) after successfully updating a product's price, ensuring new requests to that product's page receive fresh, regenerated content. The explanatory comment highlights the frequently-missed detail: a visitor's browser tab that had already navigated to this exact product page before the update, and thus already holds it in its own client-side Router Cache, will not automatically see the new price just because revalidatePath ran on the server — that specific browser needs to explicitly clear its own cached version. RefreshButton demonstrates the tool for that: calling router.refresh() from useRouter explicitly clears the current browser's Router Cache and re-fetches fresh data for the currently visible route, which is exactly the missing piece in the 'why isn't my page updating' confusion this lesson addresses.
How Real Applications Navigate Next.js's Cache Layers
- E-commerce platforms carefully call both revalidateTag and revalidatePath after price or inventory changes, understanding that these clear server-side caches but not necessarily an already-open customer's browser tab, sometimes prompting a 'refresh to see updated pricing' UI pattern.
- News sites publishing time-sensitive updates rely on understanding the Full Route Cache specifically, since a statically generated article page needs deliberate revalidation to reflect a correction or update, distinct from simply changing the underlying database record.
- SaaS dashboards use router.refresh() explicitly after a user-triggered action within the same session, ensuring the client-side Router Cache doesn't show stale data even though the user never technically left and returned to the page.
- Performance-focused engineering teams specifically monitor and reason about the Data Cache and Full Route Cache separately when diagnosing 'why is this page still slow/stale' issues, since a partially-cached page (some Data Cache misses but a cached route shell) behaves differently than expected.
- Multi-region deployments pay close attention to how the Full Route Cache is distributed and invalidated across different edge locations, since a revalidation triggered in one region needs to correctly propagate globally for the change to be visible everywhere.
Common Mistakes to Avoid
- Assuming revalidatePath or revalidateTag automatically updates an already-open browser tab's client-side Router Cache, when it only clears server-side caches.
- Confusing the Data Cache (individual fetch results) with the Full Route Cache (an entire route's rendered output), when diagnosing why a page isn't reflecting a change.
- Forgetting that Request Memoization only applies within a single render pass and has no bearing on whether a later, separate request sees fresh data.
- Not calling router.refresh() when a client-side action needs to immediately reflect a server-side change within the same browsing session.
- Overlooking that a route can only be part of the Full Route Cache if all of its underlying data fetching is itself cacheable, per the dynamic-rendering triggers covered in Lesson 2.3.
Interview Notes
- Next.js has four distinct caching layers: Request Memoization, Data Cache, Full Route Cache, and Router Cache.
- Request Memoization is the shortest-lived, scoped to a single render pass; the Data Cache and Full Route Cache persist server-side across requests.
- The Router Cache is unique in living entirely client-side, in the visitor's own browser, for instant back/forward navigation.
- revalidatePath/revalidateTag clear server-side caches (Data Cache, Full Route Cache) but not an already-open browser's client-side Router Cache.
- router.refresh() explicitly clears the current browser's Router Cache, useful for reflecting server-side changes within an already-open session.
Key Takeaways
- Understanding all four caching layers, rather than just one, is essential for correctly diagnosing 'my data isn't updating' issues in Next.js.
- Each layer has a distinct scope and lifetime, from a single render pass (Request Memoization) to an entire browsing session (Router Cache).
- revalidatePath and revalidateTag are server-side tools; router.refresh() is the client-side counterpart for an already-open browser session.
- This complete caching picture ties together concepts from Lessons 2.3, 2.4, and 2.5 into one coherent mental model.
Summary
Next.js maintains four distinct caching layers, each with a different scope and lifetime. Request Memoization is the shortest-lived, deduplicating identical fetch calls only within a single render pass. The Data Cache persists server-side across many separate requests, controlled by fetch's cache and revalidate options, as covered in Lesson 2.5. The Full Route Cache operates one level above, caching an entire route's rendered HTML and RSC payload for statically rendered routes. The Router Cache is unique in living entirely client-side, in a visitor's own browser, caching previously visited routes for instant back/forward navigation. Critically, revalidatePath and revalidateTag (from Lesson 2.4) only clear the server-side Data Cache and Full Route Cache — they do not automatically clear an already-open browser tab's client-side Router Cache, which requires an explicit router.refresh() call or a hard reload to reflect a server-side change within that same browsing session. Understanding all four layers together resolves much of the common confusion around why a page might appear stale despite a seemingly successful data update.