Understanding Next.js Cache (Part 5)
Source: Dev.to
The Bakery Analogy (API Data vs Pages)
Think of your Next.js application as a bakery.
- The API Data (the data cache) are the raw ingredients (flour, sugar, eggs) fetched from your database or external APIs.
- The Pages (the full‑route cache) are the fully baked cakes sitting in the display window.
Next.js doesn’t just cache the finished HTML (the cake); it also caches the raw JSON (the ingredients). This means that if 50 users from different locations visit your site at the exact same time, Next.js doesn’t overwhelm your database with 50 queries—it uses the cached ingredients to serve everyone instantly.
The 4 Layers of Caching
The most common point of confusion is what happens when a user hits the refresh button. Below are the four layers of the Next.js cache, illustrated with kitchen metaphors.
1. Request Memoization (the countertop/clipboard)
If three different React components on the same page all call fetch('/api/user'), Next.js deduplicates the requests: it makes the network request once and shares the result.
Note: The countertop/clipboard is wiped clean after every single page render.
2. Router Cache (the customer’s plate)
As a user navigates your app, Next.js stores the React Server Component payloads in the browser’s memory. This makes clicking the Back button feel instantaneous.
Note: This cache does not survive a hard refresh; a refresh wipes the browser’s memory (washes the plate).
3. Data Cache (the pantry)
Next.js stores the raw JSON data returned from your database across multiple user sessions.
Note: This survives a refresh. When the page is refreshed, the browser asks the server for new data, but the server simply pulls the same cached data from the pantry. This is why refreshing often doesn’t “fix” stale data.
4. Full‑Route Cache (the display window)
Next.js takes the cached data and your components, rendering them into pure, static HTML at build time.
Note: This survives a refresh as it serves the pre‑rendered HTML file until the underlying data cache is explicitly invalidated.
Taking Control of the Cache
Caching is fantastic for performance, but dynamic apps need dynamic data. Here’s how to tell Next.js to discard stale ingredients.
1. Opting Out Entirely (No Caching)
If a piece of data changes constantly (e.g., a live stock ticker or bank account balance), tell Next.js not to cache the fetch request at all:
// Fetched fresh on every single request
const res = await fetch('https://api.example.com/data', {
cache: 'no-store',
});2. Time‑Based Revalidation (Stale‑While‑Revalidate)
Tell Next.js to keep the cache for a specific amount of time before fetching fresh data in the background:
// Revalidate this data every 3600 seconds (1 hour)
const res = await fetch('https://api.example.com/data', {
next: { revalidate: 3600 },
});3. On‑Demand Revalidation (the “Invalidate” button)
When a user submits a form (e.g., updating their profile), you need to instantly clear the cache for that specific page. Do this inside a Server Action:
'use server';
import { revalidatePath } from 'next/cache';
export async function updateProfile(formData) {
await db.user.update(formData);
// Tell Next.js to throw away the cached HTML and data for this route
revalidatePath('/profile');
}The Grand Finale
Over these five articles we moved from understanding the theory of “fresh vs. stale” to mastering HTTP headers, taming React‑Query/Redux client state, and finally conquering the Next.js server cache.
Caching is no longer just a backend optimization—it is the beating heart of the frontend user experience. Master it, and you’ll build applications that feel instantaneous while saving server costs.
Now go build something fast.