Measured in your browserWe advise on speed. We practice it.Loaded just now · real numbers from this visit, not a lab score.
Page loaded
First byte
DOM ready
First paint
Largest paint
DNS lookup
TLS handshake
Transferred
Saved by compression
Requests

The stale pair — serve expired content while refetching, serve cached content while the origin burns — is the cheapest latency and availability upgrade in HTTP, and it ships as two Cache-Control extensions most origins never send. This guide deploys both safely, with the per-platform behavior differences that matter.

The two directives and what each buys

Both extensions (RFC 5861) ride the origin's Cache-Control header. stale-while-revalidate=N converts cache expiry from a latency event into a background one: an expired entry is served immediately while the cache refetches, so users never wait on revalidation — the win is pure latency, largest on expensive-to-render HTML and busy shared API reads. stale-if-error=N converts origin failure from an outage into a freshness downgrade: while the origin returns 5xx or is unreachable, the cache keeps serving the last good copy for up to N — the win is availability, and during real incidents it is the difference between "site slow to update" and "site down". They deploy together in one header and solve different problems; estates that adopt one should almost always adopt both.

Platform behavior: same header, different machines

The header is standard; the machinery is not, and the differences change what you can rely on. CloudFront has honored both directives from the origin since 2023, at no extra cost, with behavior driven purely by your header. Cloudflare honors SWR and, as of early 2026, revalidates fully asynchronously — the first post-expiry request no longer waits on the origin but is served stale immediately (cache status UPDATING) while a background fetch refreshes; watch for the status labels when debugging. Google Cloud CDN implements serve-while-stale with a platform default (a full day even if your header is silent, configurable up to a week) — but does not support stale-if-error, so origin-error resilience there needs different construction. Fastly exposes the most control: both directives honored from headers, with VCL able to customize stale behavior arbitrarily. The audit step: check what your platform does with a silent header (Google's day-long default surprises teams who thought staleness required opting in) and what status labels mark stale serves in your logs.

Choosing the windows

The SWR window should cover revalidation time with margin, not extend meaningful staleness: your origin's P99 response time for the asset class, times a small multiple — typically 30–120 seconds for HTML and API reads. Longer buys nothing (the refetch will have finished) and widens the worst-case staleness for no return. The stale-if-error window is a business decision dressed as a number: how long would you rather show yesterday's page than an error page? For most content the honest answer is long — hours to a day — because almost no incident ends in minutes and the alternative is a 5xx; for the exceptions, see the rails below. Set the windows per asset class in the same table as your TTLs (the TTL guide's deliverable), not globally: hashed assets need neither directive, HTML wants both, and fast-moving data wants SWR short and stale-if-error consciously chosen.

Safety rails: what must not serve stale

Staleness is a lie you have decided to tolerate, so enumerate where lying is unacceptable and rail those paths off. The permanent members: anything transactional or legally load-bearing (prices at checkout, availability that triggers purchases, terms, safety notices), anything access-controlled (a revoked user must not receive the stale authorized copy — auth-gated responses shouldn't be in shared caches at all, but stale windows widen the blast radius of mistakes), and status/incident pages, which must reflect reality precisely when origins are failing — serve those from separate infrastructure with no-store or near-zero TTLs. Express the rails as explicit headers on those routes (no-store, or max-age with both stale windows at 0) rather than relying on the global default, and add the negative test to CI: the checkout price endpoint must never return a stale cache status. The purge interaction is the last rail: purging removes stale copies too on the major platforms, so purge remains your emergency brake — but confirm on yours, and rehearse it during the drills from the trial guide's failure days.

Verify it's working

Deploy, then prove both behaviors. For SWR: pick a monitored URL, let it expire, request it, and confirm the response is immediate with the platform's stale/updating status while your origin logs show the background refetch — then confirm the next request is fresh. For stale-if-error: in staging (or a canary hostname), take the origin down and confirm the edge keeps answering with the last good copy and the stale status for the window you set, then recovers cleanly. Add both to your synthetic monitoring as ongoing assertions — the directives are origin-emitted, so a framework upgrade that rewrites headers can silently remove your resilience, and the first natural experiment (a real origin outage) is the wrong place to discover it. Dashboards close the loop: stale-serve counts by class belong next to hit ratio in your weekly measurement review — a rising stale-if-error count is an origin-health alarm someone should be hearing.

Get the free assessmentMore analysis