Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does stale-while-revalidate interact with s-maxage in Cache-Control header?

Just want to know around the header that I have specified for my SSR pages: public, s-maxage=3600, stale-while-revalidate=59.

Please note that my stale-while-revalidate value is 59 seconds which is way less than s-maxage value which is 1 hour. I want to know that when stale-while-revalidate value is smaller than s-maxage, what happens exactly? Is the stale-while-revalidate header ignored?

like image 767
Gauri Padbidri Avatar asked Mar 13 '26 06:03

Gauri Padbidri


2 Answers

As pointed out by @DanilaVershinin in his answer, s-maxage and stale-while-revalidate are applied to different caches - shared cache and browser cache respectively. They do not overlap with each other.


Disclaimer: this answer applies to max-age (and not s-maxage).

Setting the page's Cache-Control header to max-age=3600, stale-while-revalidate=59 means two things:

  1. The page is considered fresh for 3600 seconds (max-age=3600);
  2. The page will continue to be served from stale up to 59 seconds after that (stale-while-revalidate=59) while revalidation is done in the background.

stale-while-revalidate does not get ignored, it determines the extra time window when revalidation occurs after the page's max-age has passed (i.e. when the page is stale).

Here's the cache states across the three time windows (based on https://web.dev/stale-while-revalidate/#live-example):

0 to 3600s 3601s to 3660s After 3660s
Cached page is fresh and used to serve the page. No revalidation. Cached page is stale but used to serve the page. Revalidation occurs in the background to populate cache. Cached page is stale and not used at all. New request is made to serve the page and populate cache.

Excerpt from the HTTP Cache-Control Extensions for Stale Content spec:

Generally, servers will want to set the combination of max-age and stale-while-revalidate to the longest total potential freshness lifetime that they can tolerate. For example, with both set to 600, the server must be able to tolerate the response being served from cache for up to 20 minutes.

Since asynchronous validation will only happen if a request occurs after the response has become stale, but before the end of the stale-while-revalidate window, the size of that window and the likelihood of a request during it determines how likely it is that all requests will be served without delay. If the window is too small, or traffic is too sparse, some requests will fall outside of it, and block until the server can validate the cached response.

like image 131
juliomalves Avatar answered Mar 15 '26 16:03

juliomalves


The directive stale-while-revalidate can apply to both private (browser) 1 and public (CDN, proxy) 2 3 caches, if they support it. It starts to take effect once the object becomes stale in that cache for the first x seconds of staleness.

The Fastly docs show this nicely:

Fastly cache diagram

In your example, a browser would immediately consider the response stale, but reuse a cached response in the first 59 seconds, while revalidating it in the background. After 59 seconds, the revalidation would block the response as normal.

A proxy would first use the s-maxage and consider the response fresh for 1 hour, delivering it without revalidating. After that, it would use stale-while-revalidate (between 1:00:00 and 1:00:59) and deliver the stale response while revalidating in the background. Starting 1:01:00 after the last revalidation, the response is considered expired and will not be delivered without first revalidating.


1. MDN: Cache-Control Browser Support
2. Fastly Docs
3. Cloudfront Docs

like image 39
Owen Avatar answered Mar 15 '26 16:03

Owen



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!