nextjs-caching-architecture
The 4 layers of caching (Memoization, Data Cache, Full Route, Router Cache).
Installation
Follow the repository instructions for this skill and your agent. Review the files and dependencies before adding it to your workflow.
View source ↗GuidesSkill instructions
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)inlayout,page, andcomponentonly triggers 1 network call. -
Key: Matches URL and Options exactly.
-
Non-Fetch: For DB calls/Prisma, use React
cache()manually.import { cache } from 'react'; const getItem = cache(async (id) => db.item.findUnique({ id }));
2. Data Cache (The "Server Persistence")
-
Default:
fetchtracks 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_cachefor DB queries caching.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 orrevalidatePath()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'
- Data:
-
On-Demand (CMS/Admin):
- Use
revalidateTag('collection')for surgical updates. Better thanrevalidatePath(which nukes the whole URL).
- Use
Examples
Read the usage examples in the source repository.
View source ↗Source history
- Indexed on
- 2026-01-20
- Index updated
- 2026-01-26
- Branch
- main
Index and sync dates describe this directory. View the source repository for code history.
GitHub ↗chat Comments (0)
Sign in to join the discussion and leave a comment.
No comments yet. Be the first to share your thoughts!