The Next.js Cache (The Four Caches)
The Next.js Cache (The Four Caches)
Level 8 — Rendering Strategies & Cache The complex, multi-layered caching architecture in Next.js that spans both the server and the browser to maximize performance and minimize database queries.
1. Prerequisites
- Static Site Generation (SSG) — Another layer of this cache.
- React Server Components (RSC) — Caching data fetches in React Server Components.
2. Term Category
Data Fetching & Caching (Next.js Cache Management API): next/cache utilities (revalidatePath, revalidateTag, unstable_cache) manage Data Cache and Full Route Cache invalidation.
3. Explanation
Environment Context
- Server & Client
(1) Design Motivation — "Why did we design this?"
Next.js is designed to be fast by default. To achieve this, it aggressively caches almost everything it can. However, understanding what is cached, where it is cached, and how to clear it is the #1 source of confusion for new Next.js developers. The Next.js Cache is actually composed of four distinct layers.
(2) The Four Layers of the Cache
Layer 1: Request Memoization (Server)
- What it caches: The return values of
fetchrequests. - Lifespan: Only lasts for a single render pass of a single React component tree.
- Purpose: Prevents you from making the same API call 5 times in different components on the same page.
- How to clear: Automatically clears as soon as the page is finished rendering.
Layer 2: Data Cache (Server)
- What it caches: The persistent JSON data returned from a
fetchor database query. - Lifespan: Permanent (by default via
force-cache), across all user requests. - Purpose: Prevents hitting your backend database thousands of times for the same data.
- How to clear:
revalidatePath,revalidateTag, or time-basedrevalidate: 60.
Layer 3: Full Route Cache (Server)
- What it caches: The final rendered HTML and React Server Component Payload of a page.
- Lifespan: Permanent (This is essentially what SSG is).
- Purpose: Prevents running the React rendering engine on the server.
- How to clear: Automatically cleared when the underlying Data Cache is revalidated.
Layer 4: Router Cache (Client / Browser)
- What it caches: The React Server Component Payload (the UI) of pages the user has already visited, stored in browser memory.
- Lifespan: Lasts for the duration of the user's browser session (clears on hard refresh).
- Purpose: Makes navigating back and forth between pages (e.g., clicking the "Back" button) instantaneous because no network request is made.
- How to clear: Call
router.refresh()or trigger a Server Action.
4. Common Mistakes & Pitfalls
Mistake 1: The "Why isn't my data updating!?" panic
The mistake: A developer updates data in their database. They click a <Link> to go to the page showing that data. The data hasn't updated. They get frustrated with Next.js caching.
Why it's wrong: They are fighting Layer 4: The Router Cache. Even if you didn't cache the database query on the server, the browser remembers the UI of the page from 10 seconds ago and instantly restores it from memory to be fast.
Golden Rule: When dealing with mutations (Server Actions), always call revalidatePath() on the server. This explicitly tells Next.js to not only clear the Server Caches (Layers 2 & 3), but it also sends an instruction down to the browser to clear the Client Cache (Layer 4) so the user sees the new data!
Mistake 2: Confusing Next.js Cache Architecture Layers (Data Cache vs Full Route Cache)
The mistake: Expecting revalidateTag() to purge browser-side Router Cache instances immediately.
Why it's wrong: Next.js maintains 4 distinct cache layers: Client Router Cache, Full Route Cache (Server HTML), Data Cache (fetch data), and Request Memoization. revalidateTag() purges Data Cache & Full Route Cache, but browser Router Cache persists for 30s.
Incorrect:
/* Expecting revalidateTag() to clear client browser Router Cache instantly */
Fix:
/* Call router.refresh() on client to refresh client-side Router Cache alongside revalidateTag() */
Mistake 3: Disabling Data Cache Globally in Next.js Production Deployments
The mistake: Adding export const dynamic = 'force-dynamic' to root layout component.
Why it's wrong: Force-dynamic on root layout disables static caching across the ENTIRE web application, causing every request to execute dynamic server rendering.
Incorrect:
// app/layout.tsx
export const dynamic = 'force-dynamic'; // ❌ Disables caching globally for entire app!
Fix:
// Keep root layout static; set force-dynamic only on specific dynamic pages
5. Practice Exercises
Exercise 1: Caching Custom Database Queries with unstable_cache
Scenario:
Wrap an expensive database ORM query in unstable_cache() with custom cache tags and revalidation timers.
Requirements:
- Import
unstable_cachefromnext/cache.
Answer
Implementation
import { unstable_cache } from "next/cache";
import { db } from "@/lib/db";
export const getCachedUsers = unstable_cache(
async (role: string) => {
return db.user.findMany({ where: { role } });
},
["users-by-role"], // Key parts
{
revalidate: 3600, // Cache for 1 hour
tags: ["users"] # Tag for on-demand invalidation
}
);
Technical Explanation
unstable_cache()extends Data Cache functionality to arbitrary async functions (database queries, ORM calls, computations).tagsallow purging cached database query results on demand viarevalidateTag('users').- Crucial for caching database calls that do NOT use the
fetch()API.
Exercise 2: Purging Data Cache Entries with revalidateTag
Scenario:
Purge all cached data associated with tag 'inventory' inside a Server Action.
Requirements:
- Call
revalidateTag('inventory')in Server Action.
Answer
Implementation
"use server";
import { revalidateTag } from "next/cache";
export async function updateStockLevel(productId: string) {
// Update DB...
revalidateTag("inventory");
}
Technical Explanation
revalidateTag('tag-name')invalidates matching Data Cache entries globally across all pages.- Affects both
fetch()requests andunstable_cache()queries tagged with the same string. - Targeted cache invalidation pattern.
Exercise 3: Purging Route Segment Cache with revalidatePath
Scenario:
Purge all cached route pages under /shop using revalidatePath('/shop', 'page').
Requirements:
- Call
revalidatePath('/shop', 'page').
Answer
Implementation
"use server";
import { revalidatePath } from "next/cache";
export async function updateCatalog() {
revalidatePath("/shop", "page");
}
Technical Explanation
revalidatePath()purges static Full Route Cache HTML and associated Data Cache entries for specified URL paths.- Passing
'page'limits invalidation to the specific page component. - Core cache management API usage.
6. Related Terms
- On-Demand Revalidation (
revalidatePath,revalidateTag) — The primary tool for clearing Layers 2, 3, and 4. - Static Site Generation (SSG) — Essentially Layer 3.
- React Server Component Payload (RSC Payload) — Related concept: React Server Component Payload (RSC Payload).
- Data Caching (
force-cache,no-store) — One layer of this cache.
7. Key Takeaways
- The Next.js Cache is made of four layers: Request Memoization, Data Cache, Full Route Cache, and Router Cache.
- Request Memoization deduplicates identical
fetchcalls during a single page render. - Data Cache stores persistent data across multiple visitors on the server.
- Full Route Cache stores pre-rendered HTML on the server (SSG).
- Router Cache stores previously visited pages in the user's browser for instant backward/forward navigation.