Files
Hendrik LiebauandGitHub 02a73c59bb Rename DYNAMIC_EXPIRE and DYNAMIC_STALE to describe what they gate (#95361)
The `DYNAMIC_EXPIRE` and `DYNAMIC_STALE` constants read as if the value
itself is a dynamic expire or stale time, but every comparison is
`expire < DYNAMIC_EXPIRE` / `stale < DYNAMIC_STALE`, so the value is the
exclusive upper bound of the dynamic range: it is the smallest value
that is *not* dynamic, not a dynamic value. The names are backwards at
the boundary, which is easy to misread.

The two thresholds also gate different things. `expire` gates whether a
cache entry is included in the static prerender: below the threshold it
becomes a dynamic hole, though a short-`expire` value is still served
during a runtime prefetch. `stale` gates whether an entry is included in
a runtime prefetch or app shell.

This renames them to name that consequence: `MIN_PRERENDERABLE_EXPIRE`
and `MIN_PREFETCHABLE_STALE`. It reads correctly both at the comparison
sites (`expire < MIN_PRERENDERABLE_EXPIRE` is "below the minimum
prerenderable expire", i.e. dynamic) and at the one site that uses the
value directly, where private caches force `expire:
MIN_PRERENDERABLE_EXPIRE` precisely because it is the shortest expire
that stays prerenderable (and so is retained without being reclassified
as a short-expire dynamic hole). This is a pure rename with no behavior
change.


---

<sub>Stack created with <a
href="https://github.com/github/gh-stack">GitHub Stacks CLI</a> • <a
href="https://gh.io/stacks-feedback">Give Feedback 💬</a></sub>
2026-07-01 21:31:06 +02:00

35 lines
1.0 KiB
TypeScript

import { cacheLife } from 'next/cache'
import { Suspense } from 'react'
async function getCachedRandom() {
'use cache'
// Long-lived (stale >= MIN_PREFETCHABLE_STALE, expire >=
// MIN_PRERENDERABLE_EXPIRE): stays in the static shell.
cacheLife({ stale: 60, revalidate: 100, expire: 1000 })
return Math.random()
}
async function ShortStaleCache() {
'use cache'
// Long expire (>= MIN_PRERENDERABLE_EXPIRE, 5min) and a non-zero revalidate,
// but a stale time below MIN_PREFETCHABLE_STALE (30s). This isolates the
// short-stale exclusion: the entry is omitted from the static shell purely
// because of its short stale time, not because of a short expire or
// revalidate: 0.
cacheLife({ stale: 18, revalidate: 100, expire: 1000 })
return <p id="y">{new Date().toISOString()}</p>
}
export default async function Page() {
const x = await getCachedRandom()
return (
<>
<p id="x">{x}</p>
<Suspense fallback={<p id="y">Loading...</p>}>
<ShortStaleCache />
</Suspense>
</>
)
}