The 4 layers of caching (Memoization, Data Cache, Full Route, Router Cache).
Scanned 9/8/2026
Install to Claude Code
npx -y skills add ngxtm/devkit --skill caching --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Caching?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/ngxtm-caching-devkit)More formats (shields.io, HTML) on the badges page.
---
name: Next.js Caching Architecture
description: The 4 layers of caching (Memoization, Data Cache, Full Route, Router Cache).
metadata:
labels: [nextjs, caching, isr, revalidation]
triggers:
files: ['**/page.tsx', '**/layout.tsx', '**/action.ts']
keywords: [unstable_cache, revalidateTag, Router Cache, Data Cache]
---
# Caching Architecture
## **Priority: P1 (HIGH)**
Next.js has 4 distinct caching layers. Understanding them prevents stale data bugs.
## The 4 Layers
| Layer | Where | Duration | Purpose | Control |
| :------------------------- | :----- | :------------- | :--------------------------------------------------- | :----------------- |
| **1. Request Memoization** | Server | Per Request | Deduplicate same `fetch()` calls in one render pass. | `AbortController` |
| **2. Data Cache** | Server | Persistent | Store data across user requests. | `revalidateTag` |
| **3. Full Route Cache** | Server | Persistent | Store HTML/RSC payload. (Static Rendering). | `revalidatePath` |
| **4. Router Cache** | Client | Session (< 5m) | Navigating back/forward without server hit. | `router.refresh()` |
## 1. Request Memoization
- **Behavior**: Calling `getUser(1)` in `layout`, `page`, and `component` only triggers 1 network call.
- **Key**: Matches URL and Options exactly.
- **Non-Fetch**: For DB calls/Prisma, use React `cache()` manually.
```tsx
import { cache } from 'react';
const getItem = cache(async (id) => db.item.findUnique({ id }));
```
## 2. Data Cache (The "Server Persistence")
- **Default**: `fetch` tracks cache indefinitely (`force-cache`).
- **Scaling**:
- **Vercel**: Shared globally via KV/Blob.
- **Self-Hosted**: Stored in filesystem (Pod ephemeral storage). **Critical**: Must configure a shared `cacheHandler` (Redis) for multi-pod Kubernetes setups, otherwise pods have desynchronized caches.
- **Granular Control**: Use `unstable_cache` for DB queries caching.
```tsx
import { unstable_cache } from 'next/cache';
const getCachedUser = unstable_cache(
async (id) => db.user.find(id),
['users-key'],
{ tags: ['users'], revalidate: 60 },
);
```
## 3. Router Cache (The "Client Stale")
- **Problem**: User updates a listing, navigates back, and sees old data.
- **Cause**: Client-side Router Cache holds payload for 30s (dynamic) or 5m (static).
- **Fix**: Call `router.refresh()` in a Client Component or `revalidatePath()` in a Server Action (which automatically invalidates Router Cache).
## Strategies
- **Opt-Out (Real-Time)**:
- Data: `fetch(..., { cache: 'no-store' })`
- Route: `export const dynamic = 'force-dynamic'`
- **On-Demand (CMS/Admin)**:
- Use `revalidateTag('collection')` for surgical updates. Better than `revalidatePath` (which nukes the whole URL).
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!