Caching Architecture
Priority: P1 (HIGH)
Next.js has 4 distinct caching layers. Understanding them prevents stale data bugs.
Workflow: Configure Caching for a Feature
- Choose cache strategy — SSG (
force-cache), ISR (revalidate: N), or SSR (no-store). - Tag cacheable fetches — Add
next: { tags: ['posts'] }to fetch options. - Invalidate on mutation — Call
revalidateTag('posts')in Server Actions. - Deduplicate requests — Wrap shared data fetches with React
cache(). - Clear client cache — Use
router.refresh()after client-side mutations.
Cache Invalidation Example
Implementation Guidelines
- Next.js 15+ Standard: Use
fetchwithrevalidate: numberorcache: 'force-cache'for API calls. Useunstable_cacheor the new'use cache'(experimental) for custom data stores. - Layers: Distinguish between Data Cache (persistent across requests) and Request Memoization (React's lifecycle specific). Use
cache()from React to deduplicate fetches within a single render. - Invalidation: Use
revalidatePath('/')after mutations orrevalidateTag('tag-name')for granular cache purging. - Client Cache: Understand the Router Cache (in-memory on client) and its 30s-min lifespan. Clear it using
router.refresh(). - Static Assets: Leverage
generateStaticParamsfor pre-rendering static routes at build time. Use ISR (Incremental Static Regeneration) for content that updates periodically. - Streaming: Combine
Suspensewithfetchtriggers to prevent slow data from blocking the entire page render. - Next.js 16+: Favor
'use cache'andcacheLife()overrevalidate: numberwhere available for deterministic caching.
| Layer | Where | Control |
| :---------------------- | :----- | :----------------------------- |
| Request Memoization | Server | React cache() |
| Data Cache | Server | 'use cache', revalidateTag |
| Full Route Cache | Server | Static Prerendering |
| Router Cache | Client | router.refresh() |
Implementation Details
See Cache Components & PPR for detailed key generation, closure constraints, and invalidation strategies.
Anti-Patterns
- No
unstable_cachein Next.js 16+: Use'use cache'directive withcacheLife()instead. - No
router.refresh()for server data: PreferrevalidateTag()for targeted cache busting. - No caching user-specific data at route level: Wrap personal data in
<Suspense>with'use cache'. - No long-lived cache without tags: Assign
cacheTag()for fine-grained invalidation control.