cacheLife profiles

Fifteen profiles, seven built in and eight defined in next.config.ts, each caching the same numeric probe. They are grouped by what their lifetime does to prerendering, not by duration.

The four probe-* profiles sit on either side of a documented threshold, so you can see each boundary for yourself.

What to check

Which ones made it into the HTML. After a build, run curl -s localhost:3000/cache-life | grep -o 'data-fallback="[^"]*"' | sort -u. It lists the profiles that could not be prerendered. That should be the first group and nothing else.

Which ones move. Reload every few seconds. The short-window profiles change value on their own schedule; max and weeks never will.

The enforcement. Move any panel out of the first group and into a group without a Suspense boundary, then build. It fails and names the component.

App Shell. The difference between the last two groups only shows up in prefetching. /prefetch shows how to see it in the network tab.

The profiles

profilestalerevalidateexpireprerender
default5m15mneverprerendered-shellFramework default when no cacheLife is called.
seconds30s1s1mdynamic-holeThe only preset below a threshold. Its 1min expire keeps it out of prerenders.
minutes5m1m1hprerendered-shellFrequently updated content.
hours5m1h1dprerendered-shellSeveral updates a day.
days5m1d7dprerendered-shellDaily updates.
weeks5m7d30dprerendered-shellWeekly updates.
max5m30d365dprerendered-shellEffectively permanent. Use it for upstreams that never change.
short(custom)30s1m5mprerendered-no-shellExisting project profile. Its 300s expire is exactly on the 5min boundary, so it is still prerendered.
blog(custom)1m5m1hprerendered-no-shellExisting project profile. Prerendered, but excluded from the App Shell.
isr-15(custom)30s15s10mprerendered-no-shellFast ISR window. Background regeneration shows up after about 15 seconds.
isr-60(custom)30s1m30mprerendered-no-shellOne minute ISR window, for comparison against isr-15.
probe-no-prerender-stale(custom)10s1m10mdynamic-holestale below 30s, so it is excluded from prerenders and becomes a dynamic hole.
probe-no-prerender-expire(custom)30s20s2mdynamic-holeexpire below 5min, so it is also excluded from prerenders.
probe-no-shell(custom)1m2m15mprerendered-no-shellstale between 30s and 5min, so it is prerendered but kept out of the App Shell.
probe-shell(custom)10m2m1hprerendered-shellstale at or above 5min, so it is prerendered and App Shell eligible.

stale is a client-router concern: how long the browser reuses cached content without asking the server. revalidate is when the server starts regenerating in the background. expire is the point past which a request has to wait. Only stale and expire affect prerendering.

Dynamic holes: dynamic hole, resolved at request time

Cached, but too short-lived to prerender, so these resolve at request time behind a <Suspense> boundary. They are still shared cache entries, so two visitors within the window get the same number. They are just not in the static HTML.

seconds

suspense fallback

The only preset below a threshold. Its 1min expire keeps it out of prerenders.

probe-no-prerender-stale

suspense fallback

stale below 30s, so it is excluded from prerenders and becomes a dynamic hole.

probe-no-prerender-expire

suspense fallback

expire below 5min, so it is also excluded from prerenders.

Prerendered, not App Shell eligible: prerendered, excluded from App Shell

In the static HTML for a direct visit, but excluded from the reusable per-route App Shell that partialPrefetching prefetches. No Suspense boundary needed.

short

use cache
cacheLife
short
upstream
335ms

ran at exec h35dq3age …

probe 226,818

30s stale · 1m revalidate · 5m expire. Existing project profile. Its 300s expire is exactly on the 5min boundary, so it is still prerendered.

blog

use cache
cacheLife
blog
upstream
288ms

ran at exec dsvinnage …

probe 515,051

1m stale · 5m revalidate · 1h expire. Existing project profile. Prerendered, but excluded from the App Shell.

isr-15

use cache
cacheLife
isr-15
upstream
448ms

ran at exec oc7icsage …

probe 771,042

30s stale · 15s revalidate · 10m expire. Fast ISR window. Background regeneration shows up after about 15 seconds.

isr-60

use cache
cacheLife
isr-60
upstream
266ms

ran at exec 5xgenjage …

probe 581,256

30s stale · 1m revalidate · 30m expire. One minute ISR window, for comparison against isr-15.

probe-no-shell

use cache
cacheLife
probe-no-shell
upstream
282ms

ran at exec 48u6ifage …

probe 344,998

1m stale · 2m revalidate · 15m expire. stale between 30s and 5min, so it is prerendered but kept out of the App Shell.

Prerendered and App Shell eligible: prerendered and App Shell eligible

Fully static. These are in the HTML and in the prefetched shell.

default

use cache
cacheLife
default
upstream
279ms

ran at exec ou2yskage …

probe 35,207

5m stale · 15m revalidate · never expire. Framework default when no cacheLife is called.

minutes

use cache
cacheLife
minutes
upstream
363ms

ran at exec nleu2oage …

probe 979,077

5m stale · 1m revalidate · 1h expire. Frequently updated content.

hours

use cache
cacheLife
hours
upstream
385ms

ran at exec hn3jq4age …

probe 240,654

5m stale · 1h revalidate · 1d expire. Several updates a day.

days

use cache
cacheLife
days
upstream
345ms

ran at exec 830ul4age …

probe 529,833

5m stale · 1d revalidate · 7d expire. Daily updates.

weeks

use cache
cacheLife
weeks
upstream
365ms

ran at exec 6yxwq8age …

probe 626,847

5m stale · 7d revalidate · 30d expire. Weekly updates.

max

use cache
cacheLife
max
upstream
351ms

ran at exec za2ep5age …

probe 427,582

5m stale · 30d revalidate · 365d expire. Effectively permanent. Use it for upstreams that never change.

probe-shell

use cache
cacheLife
probe-shell
upstream
355ms

ran at exec 25p97tage …

probe 909,423

10m stale · 2m revalidate · 1h expire. stale at or above 5min, so it is prerendered and App Shell eligible.