Next.js caching layers explained: Request Memoization, Data Cache, Full Route Cache, and Router Cache. How each works and common pitfalls.
Next.js caching layers explained: Request Memoization, Data Cache, Full Route Cache, and Router Cache. How each works and common pitfalls.
BeforeMerge offers hundreds of code review rules, guides, and detection patterns to help your team ship better code.
Next.js has four caching layers. Understanding each one prevents stale data bugs and unnecessary re-fetching.
Where: Server, during a single render pass
What: Deduplicates identical fetch() calls within the same request.
// Both calls in the same render hit the network only once
const posts1 = await fetch("/api/posts");
const posts2 = await fetch("/api/posts"); // memoizedGET requests in fetch()Where: Server, persistent across requests and deployments
What: Caches the result of fetch() calls.
// Cached indefinitely (default)
fetch("https://api.example.com/data");
// Revalidate every 60 seconds
fetch("https://api.example.com/data", { next: { revalidate: 60 } });
// Never cache
fetch("https://api.example.com/data", { cache: "no-store" });Opting out at page level:
export const dynamic = "force-dynamic";
// or
export const revalidate = 0;Where: Server, persistent What: Caches the rendered HTML and RSC payload of static routes at build time.
cookies(), headers(), searchParams) are NOT cachedOpting out:
export const dynamic = "force-dynamic";Where: Client, in-memory What: Caches RSC payloads for visited routes in the browser session.
router.refresh(), revalidatePath(), or revalidateTag()fetch(url, { next: { revalidate: 3600 } }); // 1 hour
// or at route level:
export const revalidate = 3600;import { revalidatePath, revalidateTag } from "next/cache";
// Revalidate a specific path
revalidatePath("/posts");
// Revalidate by tag
fetch(url, { next: { tags: ["posts"] } });
revalidateTag("posts");revalidatePath() or revalidateTag() in your Server Action.cookies(), headers(), or searchParams to trigger dynamic rendering.router.refresh() after client-side mutations.fetch caching doesn't apply to direct DB calls. Use unstable_cache() or revalidatePath() instead.