Skip to content
C.W.K.
Stream
Lesson 09 of 09 · published

The 'use cache' Directive

~24 min · use cache, cacheLife, cacheTag

Level 0Curious
0 XP0/68 lessons0/11 achievements
0/120 XP to next level120 XP to go0% complete

Caching at the component level

Next.js 16 introduces 'use cache' as a primitive that works on entire components and functions, not just fetch(). It replaces experimental unstable_cache with a cleaner directive-based API.

Three building blocks

APIUse
'use cache'Mark a component or function as cacheable
cacheLife(profile)Set the cache duration (built-in profiles or custom)
cacheTag(...tags)Tag the cached output for on-demand invalidation

Built-in cacheLife profiles

Use a profile name and the framework picks reasonable defaults: 'seconds', 'minutes', 'hours', 'days', 'weeks', 'max'. Custom profiles can set stale / revalidate / expire independently.

How it composes with PPR

'use cache' integrates with Partial Prerendering: cached components render at build time and become part of the static shell, while uncached parts stay dynamic in the same route.

Before applying 'use cache', list every value that can change the result. Session identity, current time, and hidden module state must either be represented or excluded. Pair cacheLife with the tolerated age and cacheTag with the mutation that changes the result. After choosing a cache unit, prove reuse for equal inputs and separation for different inputs in logs. A tag that is too broad discards too much work, while one that is too narrow leaves stale results behind. Component caching does not make fetch caching obsolete. Cache the external response when several consumers share it; cache a function or rendered unit when the whole computation is the stable reusable boundary. Count executions of a slow database function across requests, test named and custom lifetimes, and update a narrow tag. Verify neighboring cached regions survive and that two users cannot receive a shared personalized result.

Code

Cache a whole component·tsx
'use cache';
import { cacheLife } from 'next/cache';

export default async function ProductList() {
  cacheLife('hours');
  const products = await db.product.findMany();
  return (
    <ul>
      {products.map(p => <li key={p.id}>{p.name} — ${p.price}</li>)}
    </ul>
  );
}
Cache a function with tag for invalidation·ts
'use cache';
import { cacheTag } from 'next/cache';

export async function getProduct(id: string) {
  cacheTag('products', `product-${id}`);
  return db.product.findUnique({ where: { id } });
}

// In a Server Action:
import { updateTag } from 'next/cache';

export async function updateProduct(id: string, data: FormData) {
  'use server';
  await db.product.update({ where: { id }, data: { /* … */ } });
  updateTag(`product-${id}`); // invalidate just this product's cache
}

External links

Exercise

Add 'use cache' to a component that renders a slow database query. Set cacheLife('hours') and verify the component is reused across requests until the next mutation tags it for invalidation.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.