stale-while-revalidate Pattern for Fast Responses
Learn how stale-while-revalidate serves cached content instantly while fetching fresh data in the background, balancing speed and freshness.
Detailed Explanation
The stale-while-revalidate Pattern
stale-while-revalidate (SWR) is a Cache-Control extension that lets the cache serve a stale response immediately while fetching a fresh copy from the origin server in the background.
How It Works
Cache-Control: max-age=60, stale-while-revalidate=30
This creates three time windows:
- 0–60s (Fresh): Cache serves the response without any network request
- 60–90s (Stale-While-Revalidate): Cache serves the stale response instantly AND triggers a background fetch to update
- After 90s: Cache must wait for a fresh response from the origin before responding
The User Experience
Without SWR, when max-age expires:
- User waits for the origin server to respond (could be 200ms–2s)
- Page feels slow after cache expires
With SWR, when max-age expires:
- User gets an instant response (stale but likely still valid)
- Origin server is contacted in the background
- Next request gets the fresh data
Real-World Configuration
Cache-Control: public, max-age=300, stale-while-revalidate=60, stale-if-error=86400
- Fresh for 5 minutes
- Serve stale + background revalidate for 1 minute after that
- If the origin errors, serve stale for up to 24 hours
SWR in Frameworks
Many frameworks embrace this pattern:
- Next.js ISR: Uses s-maxage + stale-while-revalidate for incremental regeneration
- Vercel: Supports SWR natively at the edge
- Cloudflare Workers: Respects SWR directives
- React Query / SWR library: Implements the same concept at the application level
Considerations
- Content delivered during the SWR window may be up to
max-age + stale-while-revalidateseconds old - Not suitable for content that must be perfectly fresh (use
no-cacheinstead) - Best for read-heavy workloads where slight staleness is acceptable
Use Case
A product listing page on an e-commerce site uses 'max-age=300, stale-while-revalidate=60'. During peak traffic (Black Friday), thousands of users hit the same page. For 5 minutes, all requests are served from cache with zero origin load. When the cache expires, the first request triggers a background update while all concurrent users instantly get the cached version. This prevents origin overload while keeping content no more than 6 minutes old.