Module P-7·29 min read

The four cache layers, the old fetch()-based model vs the new use cache directive, cacheLife() TTL profiles, cacheTag()/updateTag() for on-demand invalidation, and staleTimes tuning.

JJS
Written by Jatin Jain Saraf · Senior Software Engineer

P-7 — Caching in Practice: The Four-Layer Model and the use cache Directive

Who this is for: Practitioners who have built Next.js applications and have a vague sense that caching is complex, but haven't yet developed the mental model to predict what will or won't be cached, why a page is rendering dynamically when it shouldn't, or why a page is serving stale data when it should be fresh. This module builds that mental model completely — and covers the new use cache directive that Next.js 15 introduced to make the old model obsolete.


Why This Is the Hardest Topic in Next.js

Caching in Next.js has a reputation for being confusing. The reputation is earned. As of Next.js 15, there are four distinct caching layers operating simultaneously, each with its own lifecycle, scope, and invalidation mechanism. Bugs in one layer look like bugs in another. Features that work in development behave differently in production. The build output shows but the page is serving stale data.

The engineers who master Next.js are the ones who have a clear mental model of these four layers and can look at a bug or a performance problem and immediately know which layer it belongs to.


The Four Layers

LayerWhereScopeDurationInvalidation
Request MemoizationReact renderSingle requestEnds with requestAutomatic (per request)
Data CacheNext.js serverCross-requestConfigurable / indefiniterevalidateTag, revalidatePath, time-based
Full Route CacheCDN / Next.jsCross-requestIndefinite (static)revalidatePath, revalidateTag, redeploy
Router CacheBrowserCurrent session30s–5minrouter.refresh(), navigation

Each layer caches a different thing at a different granularity. Understanding what each layer holds is the key.


Layer 1: Request Memoization

What it caches: The return values of fetch() calls and React.cache()-wrapped functions, within a single server render.

Scope: A single HTTP request lifecycle. Starts when the render begins, ends when the response is sent.

Purpose: Prevents duplicate data fetching within the same render tree. If ComponentA and ComponentB both call fetch('/api/user/123') during the same page render, the fetch happens once. The second call gets the memoised result.

tsx

Important: Request Memoization only applies to fetch(). For database queries, use React.cache() (covered in F-4 and P-1) to get the same deduplication behaviour.

This layer is automatic and cannot be configured. You cannot extend it beyond a single request, and you don't need to — that's what the Data Cache is for.


Layer 2: The Data Cache

What it caches: The results of fetch() calls with caching options, and the results of unstable_cache() / use cache functions.

Scope: Persists across requests, across deployments (unless explicitly invalidated), across serverless function invocations.

Duration: Until invalidated by revalidateTag, revalidatePath, time-based expiry, or a full redeployment.

This is the layer you actively configure. In Next.js 14, you configured it via fetch() options. In Next.js 15, the preferred approach is the use cache directive.

The Old Model: fetch() Cache Options

ts

This model works but has a limitation: it only applies to fetch(). Database queries via Prisma, ORM calls, or any non-HTTP data source aren't covered.

The New Model: use cache (Next.js 15+)

use cache is a directive — like 'use server' and 'use client' — that makes a function's return value cacheable, regardless of how it fetches data:

ts

use cache can also be applied at the file level (all exports cached) or at the component level:

tsx
tsx

Sign in to keep reading

The rest of this module is free — sign in with Google to unlock it and track your progress.

Sign in & Register

Discussion

0

Join the discussion

Loading comments...

© 2026 Jatin Jain Saraf (JJS). All rights reserved.