NetcaneTechnologies

Next.js

Caching in Next.js: Route Cache, Fetch Cache, and Revalidation

How route cache, fetch cache, and revalidate work so you can tune freshness and performance.

Yasir Haleem3 min read

Next.js has multiple caching layers. Knowing how they interact keeps your app fast without showing stale data when it matters.

Route cache (full route cache)

The route cache stores the rendered output of server-rendered routes. In production, static pages are cached so repeat requests are served from cache without re-rendering. Dynamic segments (cookies, headers, searchParams, or dynamic APIs like unstable_noStore) opt that request out of the route cache so the page is rendered per request. Understand which routes are static vs dynamic so you’re not surprised by cached or uncached behavior.

Fetch cache

fetch in server components is extended by Next.js: by default it caches the response. That cache is shared across requests and builds. So the same URL fetched in a layout and a page may be deduped and cached. Use cache: "no-store" or next: { revalidate: 0 } to skip caching when you need fresh data every time. Use next: { revalidate: 60 } to revalidate every 60 seconds.

// Cached (default)
const res = await fetch("https://api.example.com/posts");
 
// Revalidate every 60 seconds
const res = await fetch("https://api.example.com/posts", {
  next: { revalidate: 60 },
});
 
// No cache
const res = await fetch("https://api.example.com/live", {
  cache: "no-store",
});

Third-party clients (axios, direct DB) are not automatically cached; use the Route Segment config or wrap data access so you can control caching (e.g. with a short revalidate or no-store for real-time data).

Revalidation

Revalidation refreshes caches. revalidatePath("/blog") or revalidateTag("posts") invalidates the route cache and fetch cache for that path or tag. Call them from Server Actions or API routes after mutations (e.g. publish a post, then revalidate the blog list and that post’s path). On-demand revalidation keeps the site fast while allowing updates to show up when content changes.

import { revalidatePath } from "next/cache";
 
export async function publishPost(id: string) {
  await db.posts.update({ where: { id }, data: { published: true } });
  revalidatePath("/blog");
  revalidatePath(`/blog/${slug}`);
}

Use tags when you want to invalidate by concept (e.g. all “posts”) without listing every path. Pass revalidateTag("posts") in the fetch that loads posts, then call revalidateTag("posts") after any change that affects that list.

Summary

Route cache stores rendered output; dynamic behavior opts out. Fetch cache caches get requests by default; use revalidate or no-store to control freshness. Use revalidatePath or revalidateTag after mutations so the right pages and data refresh. With that, you can tune caching for both speed and freshness.

About the author

Yasir Haleem is founder and lead engineer at Netcane Technologies. He builds production Next.js sites with headless CMS platforms — Strapi, Contentful, Sanity, and WordPress — with a focus on performance, SEO, and maintainable architecture.

Let's work together

Tell us about your project. We respond within one business day with a clear scope, timeline, and estimate.