Next.js Caching Explained (2027): What Actually Gets Cached and Why

Suman SharmaSuman Sharma

Next.js caching has changed more than any other part of the framework. Defaults flipped between versions, new APIs arrived, and the result is the most common production bug I see: stale data nobody can explain.

The layers

LayerWhereWhat it caches
Request memoisationServer, one requestIdentical fetches during a single render
Data cacheServer, across requestsResults of fetches/functions marked cacheable
Full route cacheServerRendered output of static routes
Router cacheBrowserVisited route segments during navigation

The modern model: opt in with "use cache"

Newer Next.js versions move toward explicit caching: dynamic by default, cache what you choose.

import { cacheLife, cacheTag } from "next/cache"; export async function getProjects() { "use cache"; cacheLife("hours"); cacheTag("projects"); return db.project.findMany(); }

After a mutation:

"use server"; import { revalidateTag } from "next/cache"; export async function createProject(data: FormData) { await db.project.create({ /* ... */ }); revalidateTag("projects"); }

Debugging stale data

  1. Check the build output. Is the route static (○) or dynamic (ƒ)?
  2. Find the cache layer. Is it a cached function, a static route, or the browser router cache?
  3. Check revalidation. Does the mutation revalidate the right tag or path?
  4. Hard refresh. If a hard refresh fixes it, suspect the router cache.

A sane default strategy

  • User-specific data: don't cache across users. Keep it dynamic.
  • Shared, slow-changing data (blog posts, product lists): cache with tags, revalidate on change.
  • External APIs with rate limits: cache with a time-based lifetime.
  • Document it: a short CACHING.md listing what's cached and how it's invalidated saves hours.

Frequently asked questions

Why is my Next.js page showing stale data?

It's usually being statically rendered or cached at one of several layers. Check whether the route is static or dynamic in the build output, and whether the data fetch or function result is cached.

What does 'use cache' do?

In recent Next.js versions with Cache Components enabled, 'use cache' marks a function, component, or route as cacheable. You control lifetime with cacheLife and invalidation with cacheTag and revalidateTag.

How do I revalidate after a mutation?

Call revalidatePath or revalidateTag (or the newer equivalents in your Next.js version) inside the server action or route handler that performs the mutation.

Contact

Get in Touch

Want to call me? book a call and I'll respond in the available time slot. I will ignore all soliciting.