Loading content…
Loading content…
Deep dive into the 4 Next.js caching layers: Request Memoization, Data Cache, Full Route Cache, Router Cache, and on-demand revalidation
| Cache Layer | What is Cached | Where | Lifetime | Purpose |
|---|---|---|---|---|
| Request Memoization | fetch API responses | Server (Memory) | Single request lifecycle | Deduplicates requests in the same render tree |
| Data Cache | fetch responses & database results | Server (File System / Redis) | Persistent (survives restarts) | Caches fetched data across user requests |
| Full Route Cache | Rendered HTML & RSC Payload | Server (File System) | Persistent (until revalidated) | Minimizes server CPU load by serving static pages |
| Router Cache | RSC Payload (client-side) | Client Browser (Memory) | Session-based (cleared on refresh) | Speeds up back/forward navigation in the app |
Next.js Caching Layers Diagramfetch API to automatically deduplicate requests with the same URL and options. If three components in your page tree fetch the same current user details, only one network request is sent to the database or API.// app/layout.tsx
async function getUser() {
const res = await fetch("https://api.example.com/user");
return res.json();
}
export default async function Layout({ children }: { children: React.ReactNode }) {
const user = await getUser(); // First fetch: calls database
return (
<html>
<body>
<Header user={user} />
{children}
</body>
</html>
);
}
// app/page.tsx
async function getUser() {
const res = await fetch("https://api.example.com/user");
return res.json();
}
export default async function Page() {
const user = await getUser(); // Second fetch: returns cached result instantly!
return <main>Welcome back, {user.name}</main>;
}
// 1. Cached by default (persistent)
const res = await fetch("https://api.example.com/products");
// 2. Opt-out: Fetch fresh data on every request
const res = await fetch("https://api.example.com/products", {
cache: "no-store"
});
// 3. Time-based revalidation: Cache for 1 hour (3600 seconds)
const res = await fetch("https://api.example.com/products", {
next: { revalidate: 3600 }
});
Common Pitfall
fetch GET requests. If you use a database ORM like Prisma, Mongoose, or pg-pool, requests are not memoized automatically. You must wrap your query functions in React's custom cache utility to prevent duplicate queries.npm run build), Next.js renders your pages into static HTML and React Server Component (RSC) payloads. If a route uses only cached data and has no dynamic dependencies, it is pre-rendered static.cookies() or headers()searchParams)cache: "no-store" or revalidate: 0import { cookies } from "next/headers";
export default async function DashboardPage() {
// Calling cookies() automatically opts this route out of Full Route Cache
const cookieStore = await cookies();
const token = cookieStore.get("session")?.value;
const res = await fetch("https://api.example.com/profile", {
headers: { Authorization: `Bearer ${token}` }
});
const profile = await res.json();
return <div>Welcome, {profile.name}</div>;
}
<Link> to a previous page loads instantly without checking the server.Senior Developer Wisdom
router.refresh() hook inside client components, or trigger a Server Action that calls revalidatePath() or revalidateTag() on the server.// lib/data.ts
export async function getProducts() {
const res = await fetch("https://api.example.com/products", {
next: { tags: ["products"] } // Assign cache tag
});
return res.json();
}
// app/actions.ts
"use server";
import { revalidateTag, revalidatePath } from "next/cache";
export async function addProduct(formData: FormData) {
// 1. Save new product in DB
await db.product.create({
name: formData.get("name")
});
// 2. Clear all cache entries tagged with "products"
revalidateTag("products");
// 3. Clear cache and trigger UI update for the products page
revalidatePath("/products");
}
Pro Tip
revalidateTag to keep your site updated without manual rebuilds.Caching & Revalidation Checklist
revalidateTag to purge caches instantly when data changes.Marking it complete updates your roadmap progress percentage.