Our Journey with Caching
Key Points
- Two-mode model: 'use cache' (static) vs <Suspense> (dynamic)
- Tagging and TTL control with cacheTag and cacheLife
- Experimental opt-in via canary + experimental.dynamicIO
Summary
Next.js introduces an experimental, simpler caching model built on two concepts: using <Suspense> to opt into dynamic (uncached, streaming) server data, or marking a segment as static/cached with the "use cache" directive. Async functions can also be made cached by adding "use cache" inside them. New cache primitives—cacheTag and cacheLife—let you tag and control lifetimes, and cache keys are derived automatically from arguments and closures. This undoes the previous default caching of fetch(); you’ll get build/runtime errors if you use async data without choosing a mode. The feature is experimental and opt-in (canary + experimental.dynamicIO).
Key Points
- Two-mode model:
- <Suspense> => dynamic data fetching, streaming, no implicit caching.
- "use cache" (per page/layout/function) => whole segment is cached and can be statically rendered.
- If a segment uses async data without declaring a mode, the runtime/build will throw an error to force an explicit choice.
- You can add "use cache" inside any async function to create a cached function; cache key auto-includes args and closures.
- cacheTag(...) lets you tag entries and later call revalidateTag(...) from a Server Action to invalidate by tag.
- cacheLife("minutes" | "hours" | "days" | "weeks" | "max" | etc.) controls cache lifetime/stale and expire behavior without exact seconds math.
- Partial caching is supported: mark layouts/pages independently and mix static and dynamic segments.
- Experimental: enable via canary (npx create-next-app@canary) and next.config.ts experimental.dynamicIO; recommended only for greenfield or testing now.
Practical advice for engineers:
- For iterative or highly dynamic pages, wrap data components with <Suspense>.
- For pages you want statically rendered, add "use cache" at the top of the page/layout or inside specific async helper functions.
- Use cacheTag + revalidateTag for targeted invalidation and cacheLife for approximate TTLs.