ISR — revalidation windows
Four cached scopes at four speeds, against upstreams that move at roughly matching rates: crypto prices every few seconds, station measurements every fifteen minutes, reference rates once a weekday, and repository counters continuously.
Watch each panel’s age, which ticks live in your browser. When it passes the profile’s revalidate value, the entry is eligible for regeneration.
What to check
The two-reload rule. Let the market panel’s age pass 15s. Reload once: the stamp does not move — you were served the stale entry while regeneration kicked off in the background. Reload again: now it moves.
Cached against live. The two market panels read the same endpoint in the same request. Their prices drift apart within the window and re-converge when the cached one regenerates.
Two clocks. The station panel has a 60s cache window but its observed time only advances every 15 minutes, because that is the upstream’s publication interval. “The cache entry is fresh” and “the data is new” are different claims, and the FX panel makes the same point more starkly — a 5 minute window over data that changes once a weekday.
From the shell: for i in $(seq 1 6); do curl -s localhost:3000/isr | grep -m1 -o 'data-exec="[^"]*"'; sleep 5; done — the id repeats, then changes, on that two-request cadence.
Fast window — 15 seconds
cacheLife('isr-15'): stale 30s, revalidate 15s, expire 10m. The left panel is cached; the right one is the same fetch with no cache at all, rendered in the same request.Market — cached 15s
use cache- cacheLife
- isr-15
- cacheTag
- market
- upstream
- 73ms
ran at exec a3629sage …
- bitcoin$84,342 · published 21:02:40Z
- ethereum$2,688.02 · published 21:02:30Z
Tagged 'market', so the buttons below can expire it without waiting for the window.
Market — live
suspense fallbackstreaming at request time — this is what ships in the static shell
Medium and slow windows
Station — 60s window
use cache- cacheLife
- isr-60
- cacheTag
- stations, stations:london
- upstream
- 120ms
ran at exec 81mg1iage …
station London
- temperature
- 17.7°C
- humidity
- 71%
- wind
- 8.3km/h
- pressure
- 1020.3hPa
- elevation
- 16m
- observed
- 2026-09-24T21:00Z
The upstream publishes on a 15 minute interval, so the observed time changes far less often than this cache does. Two different freshness clocks, which is worth keeping straight.
FX rates — 5m window
use cache- cacheLife
- blog
- cacheTag
- fx
- upstream
- 396ms
ran at exec 4247jnage …
1 USD · published 2026-09-24
- CHF0.82775
- EUR0.87974
- GBP0.75645
- JPY158.85
ECB reference rates publish once per weekday. A 5 minute window over daily data is mostly wasted work — which is the point: match the window to the upstream, not to a habit.
Repo counters — 1h window
use cache- cacheLife
- hours
- cacheTag
- repo
- upstream
- 191ms
ran at exec yjwurrage …
- stars
- 142,426
- forks
- 32,786
- open issues
- 3,481
- pushed
- 2026-09-24T21:04:48Z
A rate-limited upstream is the textbook case for a long window. A 403 here means the hourly quota is gone; it resets on its own and nothing else depends on it.
Skip the wait
Invalidate an ISR window early
revalidateTag('market', 'max')— Stale-while-revalidate. The next reload still shows the OLD stamp; the one after shows the new one.revalidateTag('market', { expire: 0 })— No stale window. The very next reload blocks on a fresh fetch and the stamp moves immediately.revalidateTag('stations:london', { expire: 0 })— Same thing for the station panel — note the other panels are untouched.