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 cacheto 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.
Run it. The first call 'computes'; the second is served from the cache. Try clearing the cache and running again.
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.