BuildBot

Foundations

The Next.js 16 caching model

Lesson 2 of 7

What you'll learn

  • Understand why Next.js 16 made caching explicit
  • Use use cache to cache expensive, shareable work
  • Know what should never be cached (per-user data)

Earlier versions of Next.js cached aggressively and implicitly — which led to a lot of "why is my data stale?" confusion. Next.js 16 flips this: nothing is cached unless you ask for it. All dynamic code runs at request time by default.

Opting into the cache

You mark a function or component as cacheable with the use cache directive, and tune its lifetime with cacheLife and cacheTag:

import { unstable_cacheLife as cacheLife } from "next/cache";

async function getCourseCatalog() {
  "use cache";
  cacheLife("hours");
  return db.courses.findMany();
}

Cache things that are shared across users and change rarely: a marketing page, a published course catalog, lesson content. Keep things per-user and live — progress, entitlements, the signed-in user — dynamic.

Never cache identity

A signed-in user's progress or permissions must render fresh every request. Cache the lesson content (same for everyone); never cache whether this user finished it.

Invalidation

When content changes, you invalidate by tag rather than waiting for a timer:

import { revalidateTag } from "next/cache";
// after a publish webhook fires:
revalidateTag("course-catalog");

The exercise below is a tiny model of cache-vs-fresh. The getCached function pretends to be expensive; run it twice and watch the cache hit on the second call.

Cache hit vs. miss

Run it. The first call 'computes'; the second is served from the cache. Try clearing the cache and running again.

Loading editor…
Knowledge check

In the Next.js 16 caching model, what happens to code that you do not explicitly mark as cacheable?

Next up: real data. We'll design a Convex schema and learn why indexes are mandatory.

Saved on this device. Sign in to sync your progress everywhere.