Every cached entry has three clocks, and cacheLife sets them. stale is how long the browser may reuse its copy without asking the server. revalidate is how old the server's copy may get before the next request triggers a background regeneration. expire is when the old copy stops being served at all.
| Profile | stale | revalidate | expire |
|---|---|---|---|
| default | 5 minutes | 15 minutes | never |
| seconds | 30 seconds | 1 second | 1 minute |
| minutes | 5 minutes | 1 minute | 1 hour |
| hours | 5 minutes | 1 hour | 1 day |
| days | 5 minutes | 1 day | 1 week |
| weeks | 5 minutes | 1 week | 30 days |
| max | 5 minutes | 30 days | 1 year |
Pass a profile name, a custom name defined under cacheLife in next.config.js, or an object for a one-off; omitted keys fall back to default.
import { cacheLife } from "next/cache";
import { bump } from "../counter";
async function Ticker() {
"use cache";
cacheLife({ stale: 30, revalidate: 5, expire: 3600 });
return <p>generated at {new Date().toISOString()} — render #{bump("timed")}</p>;
}Requesting that page every two seconds shows exactly what stale-while-revalidate means:
t= 0s generated at 2026-09-22T05:57:55.573Z <- build-time entry, already stale t= 2s generated at 2026-09-22T05:58:48.130Z t= 4s generated at 2026-09-22T05:58:48.130Z t= 6s generated at 2026-09-22T05:58:48.130Z t= 8s generated at 2026-09-22T05:58:54.706Z t=10s generated at 2026-09-22T05:58:54.706Z t=12s generated at 2026-09-22T05:58:54.706Z t=14s generated at 2026-09-22T05:59:01.362Z
No request ever waits. The first one past the five-second mark is served the old value and starts the regeneration; what it produced appears on the following request. That is why revalidate: 5 yields a new timestamp roughly every six seconds rather than exactly every five.
Short lifetimes change where content can live. A revalidate of 0, or an expire under five minutes, keeps the entry out of prerenders — it becomes a hole filled at request time. A stale under 30 seconds does the same, because a prefetch would expire before the user could click; the client router enforces a 30-second floor and sends the real number in the x-nextjs-stale-time header. Of the presets only seconds crosses a threshold, through its one-minute expire.