Search

PythonReactSEOPDF
GitHub Skill

nextjs-caching-architecture

The 4 layers of caching (Memoization, Data Cache, Full Route, Router Cache).

HoangNguyen0403☆ 143 Repository stars48 Repository forks

Installation

Follow the repository instructions for this skill and your agent. Review the files and dependencies before adding it to your workflow.

View source ↗Guides

Skill 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) 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.

    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.

    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).

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)

chat_bubble_outline

No comments yet. Be the first to share your thoughts!