
An expired CDN cache entry does not always have to make a user wait for the origin. The HTTP Cache-Control directives stale-while-revalidate and stale-if-error let CloudFront serve an expired response under controlled conditions. The first reduces latency while the CDN refreshes content in the background; the second improves availability when the origin is unavailable or returns an applicable server error.
These directives solve different problems. stale-while-revalidate is primarily a performance mechanism: serve the old response now and update it asynchronously. stale-if-error is a resilience mechanism: use the old response instead of passing an origin failure to the viewer. Their real behavior also depends on freshness rules, the CloudFront maximum TTL, error caching, custom error responses, and whether the object still exists at a particular edge location.
What happens after a CDN cache entry expires?
Without a stale-content policy, the first request after max-age or s-maxage expires normally triggers revalidation. CloudFront contacts the origin. If the object is unchanged, the origin can return 304 Not Modified; if it changed, the origin returns 200 OK with the new representation.
The viewer that triggers this process may have to wait for the origin. If the origin is slow, scaling, or temporarily unavailable, the delay can grow or become a 5xx response. Stale-content directives use the previously cached representation as a controlled buffer.
| Stage | Object state | Typical behavior |
|---|---|---|
| Fresh period | Still within max-age or s-maxage | Serve directly from cache without origin validation. |
| SWR window | Expired but still within stale-while-revalidate | Serve stale content immediately and refresh it in the background. |
| SIE window | Expired, and the origin is unreachable or returns an applicable 5xx error | Use the stale response instead of the origin error. |
| All permitted windows have ended | The stale response can no longer be used | Wait for the origin or return an error or custom error page. |
What is stale-while-revalidate?
stale-while-revalidate, often abbreviated as SWR, lets CloudFront return an expired cached response while it asynchronously checks the origin for an updated version. The request that triggers the refresh therefore does not have to absorb the full origin latency.
Cache-Control: public, max-age=3600, stale-while-revalidate=600
This policy means:
The object is fresh for the first 3,600 seconds.
After it expires, a new request can receive the old version immediately while CloudFront refreshes it in the background.
The SWR allowance is 600 seconds, subject to CloudFront's maximum TTL.
After a successful refresh, later requests receive the new version and a new freshness period begins.
SWR is useful for article listings, product catalogs, public API results, blogs, and configuration manifests where a short period of staleness is acceptable. It is generally unsuitable for account balances, inventory reservations, one-time credentials, authorization state, or checkout prices that must be current.
What is stale-if-error?
stale-if-error, or SIE, lets CloudFront serve an expired cached response when it cannot reach the origin or when the origin returns an error in the 500–599 range. Its main purpose is availability during an origin incident, not faster routine refreshes.
Cache-Control: public, max-age=3600, stale-if-error=86400
Here, the object is normally fresh for one hour. If an applicable origin error occurs after expiration, CloudFront may use the old response during the 86,400-second SIE window. This is not a guarantee that every edge can serve the object for a full day: the old object must still be present in that edge cache, and the maximum TTL must not shorten the effective window.
SIE is not a backup system. Edge objects can be evicted because of low demand or cache-space management. Critical services still need health checks, redundant origins, origin failover, database recovery, and a tested deployment rollback process.
Can SWR and SIE be used together?
Yes. Combining them gives a more complete policy:
Cache-Control: public, max-age=3600, stale-while-revalidate=600, stale-if-error=86400
The response has three layers of behavior:
For the first hour, CloudFront serves a fresh cached response.
After expiration, it can serve the old response for up to 10 minutes while updating it in the background.
If the origin is unreachable or returns an applicable server error, it can use the stale response within the SIE allowance.
The two stale windows are independent directives. Do not assume they always form a simple “one hour plus ten minutes plus one day” timeline. Request timing, the revalidation result, cache residency, and the CloudFront maximum TTL all affect the outcome.
How do max-age, s-maxage, and CloudFront TTLs interact?
max-age can affect browsers and shared caches. s-maxage specifically controls shared caches such as CDNs and takes precedence for CloudFront when present. To let browsers recheck sooner while keeping an edge response fresh longer, use separate values:
Cache-Control: public, max-age=60, s-maxage=3600, stale-while-revalidate=600, stale-if-error=86400
In this example, the browser freshness period is 60 seconds and the shared CDN freshness period is 3,600 seconds. SWR and SIE describe when the selected representation may be used after that freshness period.
CloudFront cache policy values—Minimum TTL, Default TTL, and Maximum TTL—also affect the result:
Maximum TTL limits stale windows. CloudFront will not use a stale response longer than the smaller of the relevant stale directive and the maximum TTL.
Use a positive Minimum TTL carefully. CloudFront may cache a response for at least that duration even when the origin includes
no-cache,no-store, orprivate.Use
stale-if-error=0when stale fallback must be disabled. This can be appropriate for sensitive state, authorization, or fail-closed endpoints.Default TTL matters mainly when the origin provides no cache lifetime. Avoid relying on one default for routes with very different freshness requirements.
How is stale-if-error different from CloudFront error caching?
| Mechanism | What it serves or caches | Main purpose |
|---|---|---|
stale-if-error | A previously successful response that is now expired | Keep normal content available during an origin failure. |
| Error Caching Minimum TTL | The origin's 4xx/5xx response or a configured custom error page | Reduce repeated origin requests during an incident. |
| Custom error response | A predefined error page, optionally with a changed viewer status code | Provide a controlled failure experience when no stale response is available. |
CloudFront caches error responses for 10 seconds by default, and the Error Caching Minimum TTL can be configured per status code. A value that is too short can amplify origin traffic during an outage; a value that is too long can keep showing an error after the origin recovers. When SIE and a custom error page both apply, CloudFront first attempts to serve eligible stale content. If none is available, it can use the configured custom error response.
Which content should be allowed to go stale?
| Content type | Recommendation | Reason |
|---|---|---|
| Static articles, documentation, product information | Usually suitable for both SWR and SIE | A short period of staleness is low risk and can reduce origin load. |
| Product listings and public catalogs | Use a short SWR and evaluate SIE carefully | Balance speed against price and inventory freshness. |
| Public configuration or version manifests | Decide based on client compatibility | An old version may preserve service or delay an urgent fix. |
| Sessions, permissions, and account profiles | Usually do not cache in a shared CDN | Staleness can expose private data or outdated permissions. |
| Payments, balances, and order submissions | Do not use stale success responses as fallback | An incorrect business state can be worse than a clear error. |
| Security notices or withdrawn content | Shorten or disable stale windows | Old content may delay an important correction or takedown. |
How to add the Cache-Control policy at the origin
Nginx example
location /articles/ {
add_header Cache-Control "public, max-age=300, s-maxage=3600, stale-while-revalidate=600, stale-if-error=86400" always;
}Apache example
<Location "/articles/"> Header always set Cache-Control "public, max-age=300, s-maxage=3600, stale-while-revalidate=600, stale-if-error=86400" </Location>
Application response example
Cache-Control: public, max-age=300, s-maxage=3600, stale-while-revalidate=600, stale-if-error=86400 ETag: "article-20260817-v3" Last-Modified: Mon, 17 Aug 2026 03:20:00 GMT
Do not apply one header to the entire site without classifying routes. Articles, account pages, APIs, downloads, and errors have different risk profiles. For responses involving cookies, authorization, or user identity, first prove that one user's content cannot be shared with another.
How to verify the configuration
1. Inspect the origin and CDN response headers
curl -I https://www.example.com/articles/test-page
Confirm that the final response contains the intended Cache-Control policy. Record Age, ETag, Last-Modified, Via, and the CloudFront cache-status header. Test the CDN URL, not only the origin, because an intermediary or response-headers policy may alter the result.
2. Observe freshness and background refresh
Use shorter values in a test environment:
Cache-Control: public, max-age=20, stale-while-revalidate=30, stale-if-error=120
Make repeated requests to populate the cache, wait for the 20-second freshness period to end, then change the origin object. Check whether the first request still returns the old response quickly and whether later requests switch to the new version.
3. Simulate an origin failure
Do this only on a controlled test distribution. First ensure that the edge has a successful cached response. Then make the test origin return 503 or become temporarily unreachable. Verify whether CloudFront serves the stale object, restore the origin, and confirm that the cache updates instead of remaining stale indefinitely.
4. Test from multiple regions
CloudFront caches are distributed across edge locations. A stale object present in one location may not exist in another. SIE therefore does not replace origin redundancy, monitoring, or deliberate cache warming.
Common configuration mistakes
Treating SWR as a scheduled proactive refresh
SWR generally still needs a request after expiration to trigger revalidation. A low-traffic object may receive no request for a long time or may be evicted earlier. Use a deployment workflow, warming, or scheduled requests when updates must occur at a precise time.
Assuming SIE covers every type of error
AWS documents SIE for an unreachable origin or an origin response in the 500–599 range. Do not assume that 401, 403, or 404 responses will automatically use an old successful response; those statuses normally represent authorization, resource existence, or request problems.
Setting response headers without checking Maximum TTL
If the CloudFront maximum TTL is shorter than the intended stale window, a large SWR or SIE value will not be fully effective. Review origin headers and the cache behavior's minimum, default, and maximum TTLs together.
Using long stale windows for real-time business data
Old prices, inventory, permissions, or security states can create business and compliance risks. Availability is not always the safest goal; when stale data can cause greater harm, an explicit failure is better than a successful but incorrect response.
Forgetting stale windows during an urgent takedown
If content must disappear immediately, do not wait for TTL, SWR, or SIE to expire naturally. Create a CloudFront invalidation and include all relevant URL, query-string, and language variants.
Recommended configuration process
Classify content by risk. Decide which routes tolerate an old response and which must always use current or private data.
Separate browser and CDN freshness. Use
max-ageands-maxageinstead of forcing all cache layers to share one lifetime.Keep SWR relatively short. It should cover normal background refresh time, not hide a long deployment failure.
Align SIE with recovery objectives. Consider typical incident duration, staleness risk, and origin failover capability.
Review CloudFront Maximum TTL. Ensure it does not unintentionally truncate the stale-content window.
Configure error caching too. Prevent an origin request storm when stale content is unavailable.
Maintain an emergency invalidation process. Operators must be able to withdraw cached content quickly.
Monitor content versions. Correlate ETag, cache status, Age, origin status code, and latency to determine which version users receive.
Frequently asked questions
Will CloudFront always serve stale content after expiration?
No. The directive, time window, error condition, and cache policy must permit it, and the object must still exist in the relevant edge cache. Low-demand objects can be evicted before the configured window ends.
Will stale-while-revalidate make every user see old content?
Normally, no. CloudFront serves the old response while revalidating, then uses the updated version after a successful refresh. If refreshes keep failing, SIE, maximum TTL, and error-response settings determine what happens next.
Can stale-if-error replace multi-origin failover?
No. SIE can only use a previously cached response, does not guarantee that every edge has a copy, and cannot execute dynamic operations that require the origin. It is an additional resilience layer, not a complete failover design.
Should s-maxage and max-age be used together?
Yes, when browsers and the CDN need different freshness periods. CloudFront, as a shared cache, uses s-maxage when it is present, while browsers normally follow max-age.
How can I stop CloudFront from serving stale objects during an origin error?
AWS documents stale-if-error=0 for disabling that fallback. Also review Minimum TTL, error caching, and custom error responses so the complete behavior follows the intended fail-closed policy.
Conclusion
stale-while-revalidate and stale-if-error both allow a CDN to use expired content, but for different reasons. SWR trades a short period of staleness for lower refresh latency. SIE trades staleness for availability during an origin failure. Neither directive should be evaluated without max-age, s-maxage, CloudFront Maximum TTL, and error caching.
A sound policy starts with content risk. Static articles and public catalogs can often use controlled stale windows. Account, authorization, payment, and real-time state should be cached cautiously or explicitly use stale-if-error=0. Before production, test normal expiration, background refresh, origin 5xx responses, origin unavailability, emergency invalidation, and regional cache differences so that “stay available” never becomes “serve the wrong version indefinitely.”
References
AWS CloudFront Developer Guide: Manage how long content stays in the cache (expiration), reviewed August 17, 2026
AWS CloudFront Developer Guide: Control how long CloudFront caches errors, reviewed August 17, 2026
IETF RFC 5861: HTTP Cache-Control Extensions for Stale Content, reviewed August 17, 2026
MDN: Cache-Control, reviewed August 17, 2026