CONCEPT Cited by 2 sources
Stale-while-revalidate cache¶
Definition¶
Stale-while-revalidate (SWR) is a caching semantic where a cache is permitted to serve a stale entry immediately while it revalidates (or re-fetches) in the background. The client gets a bounded-stale response with zero extra latency; the origin sees one refresh request per window rather than a burst of synchronous misses.
Originally codified for HTTP caches as Cache-Control:
stale-while-revalidate=<seconds> in
RFC 5861, it
has become a generic cache-design primitive that shows up
everywhere a cache has (a) a freshness lifetime and (b) a
background-refresh capability:
- HTTP intermediary caches — CDNs, reverse proxies.
- Client-side frameworks —
swr/ React Query on the browser. - Application-tier in-process caches — Caffeine's
refreshAfterWrite, Guava'sLoadingCachewith refresh, Go'sgolang/groupcache. See concepts/async-loading-cache-stale-window for the Caffeine-specific form. - Service-mesh / gateway caches — some proxies emit SWR semantics on upstream cache-control directives.
Why it's useful¶
A plain TTL cache has exactly two states per key: fresh (hit) or expired (miss). Every boundary crossing from fresh to expired is a latency spike + stampede risk. SWR adds a third state — "stale but servable" — between expired and fresh, during which reads are fast and the cache takes responsibility for bringing the value back up to date.
This decouples user-perceived latency from freshness-refresh latency. The origin round-trip happens on a background thread; the serving path never waits on it.
Three common knobs¶
- TTL (fresh lifetime) — up to this point the value is just fresh; no refresh is triggered on read.
- Stale window (or SWR duration) — between TTL and
TTL + stale_window, reads serve the value and also trigger refresh. Some systems (Caffeine) combine TTL and stale window by configuring a shorterrefreshAfterWritealongsideexpireAfterWrite. - Maximum staleness — at some point the stale value is
no longer acceptable; reads block on a fresh fetch.
Implementation-specific; Caffeine uses
expireAfterWriteas the hard ceiling.
Trade-offs vs. alternatives¶
| Alternative | What SWR does better | What SWR does worse |
|---|---|---|
| Plain TTL | No tail-latency spike on expiry; no stampede | Bounded-stale reads instead of strict-fresh-or-miss |
| Write-through | Keeps read latency low without write coupling | Eventually-consistent instead of synchronously updated |
| Manual refresh-ahead scheduler | Doesn't require a schedule; refresh is traffic-driven | Low-traffic keys still take synchronous misses when TTL elapses |
| Event-driven invalidation | No invalidation plumbing; origin-read is self-healing | Can't reflect deletes synchronously; requires TTL as backstop |
Seen in¶
-
Cloudflare — When DNSSEC goes wrong: how we responded to the
.deTLD outage (2026-05-06). Canonical wiki production instance at the DNS recursive-resolver altitude via RFC 8767 — DNS's equivalent of RFC 5861 for recursive resolvers. Cloudflare's systems/cloudflare-1-1-1-1-resolver|1.1.1.1 (via Big Pineapple) kept NOERROR rates stable for ~3 hours during the DENIC.deDNSSEC break by continuing to serve expired cached records when upstream fetches returned unverifiable signatures. "When upstream resolution fails, a resolver may continue serving expired cached records rather than returning an error. This significantly cushions the impact of an upstream outage, buying time for operators to respond." This is the availability-during-upstream-failure axis of SWR (RFC 8767's explicit motivation) as distinct from RFC 5861's stampede-suppression + tail-latency axis — same primitive, different load-bearing use case. See patterns/serve-stale-over-servfail. (Source: sources/2026-05-06-cloudflare-when-dnssec-goes-wrong-de-tld-outage.) -
— Zalando's PRAPI uses Caffeine's async-loading cache with a 60-second TTL and a trailing 15-second stale window for this exact reason: in the last 15 s of an entry's life, a read triggers a background DynamoDB refresh while the cached value is returned synchronously. The pattern is load-bearing for PRAPI's single-digit-ms P99 because it absorbs the would-be tail spike of TTL expiry.
-
sources/2026-04-21-vercel-preventing-the-stampede-request-collapsing-in-the-vercel-cdn — Vercel describes the HTTP-level realisation via
Cache-Controldirectives and request-collapsing in the CDN edge (referenced here as a sibling HTTP-altitude instance). -
GitHub Engineering — From latency to instant: Modernizing GitHub Issues navigation performance (2026-05-14). Canonical wiki browser-altitude instance backed by IndexedDB. The
issues#showroute renders immediately from a local IndexedDB-backed cache (with a synchronous in-memory tier in front for hot payloads), then issues a background fetch and reconciles the in-memory store on diff. "Read path: on soft navigation, attempt to hydrate from local cache first and render immediately. Revalidation path: issue a background network request for freshness and reconcile the in-memory store if data changed. Failure behavior: when network is degraded, users still get a usable page from cache, with freshness reconciled once connectivity recovers, introducing a new graceful-degradation model." Server/cache divergence rate measured at 4.7 % and treated as an explicit operating envelope. Cache-hit ratio ~33 % at launch (clearing the team's pre-set ~30 % viability threshold) → ~96 % after preheating was added. This is the wiki's first instance of SWR at the browser / client-application altitude with persistent storage as the cache substrate, distinct from the Caffeine application-cache, DNS-resolver, and HTTP-CDN altitudes — same primitive, fourth load-bearing altitude. See patterns/stale-while-revalidate-from-indexeddb. (Source: sources/2026-05-14-github-from-latency-to-instant-modernizing-github-issues-navigation-performance.)
Related¶
- concepts/async-loading-cache-stale-window — the application-cache realisation at the Caffeine altitude
- concepts/cache-ttl-staleness-dilemma — the tension SWR resolves
- concepts/cache-stampede — what SWR also suppresses at near-expiry
- concepts/cache-control-aware-grace-period — a related HTTP-cache primitive for cross-service freshness budgets
- systems/caffeine · patterns/async-refresh-cache-loader
- concepts/dns-resolver-caching · patterns/serve-stale-over-servfail — the DNS-resolver altitude realisation via RFC 8767; same primitive, availability-during-upstream-failure motivation.
- concepts/fail-stale — the general failure-mode-default principle that both RFC 5861 SWR and RFC 8767 serve-stale specialise.
- systems/indexeddb — browser-persistent storage substrate for the GitHub-Issues-altitude SWR realisation.
- patterns/stale-while-revalidate-from-indexeddb — the named pattern for the browser-altitude realisation.
- concepts/preheating — paired cache-population discipline that drives cache-hit ratio higher without proportionally increasing network volume.