From c70929ddaf8f29463131d1c431882c183eaed353 Mon Sep 17 00:00:00 2001 From: Tim Kornhammar Date: Tue, 24 Feb 2026 21:06:15 -0600 Subject: [PATCH 1/6] Changelog: Asynchronous stale-while-revalidate (Cache) --- ...026-02-24-async-stale-while-revalidate.mdx | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 src/content/changelog/cache/2026-02-24-async-stale-while-revalidate.mdx diff --git a/src/content/changelog/cache/2026-02-24-async-stale-while-revalidate.mdx b/src/content/changelog/cache/2026-02-24-async-stale-while-revalidate.mdx new file mode 100644 index 000000000000000..5165751e3dbdeef --- /dev/null +++ b/src/content/changelog/cache/2026-02-24-async-stale-while-revalidate.mdx @@ -0,0 +1,26 @@ +--- +title: Asynchronous stale-while-revalidate +description: Stale-while-revalidate now returns stale content immediately while revalidation happens in the background, eliminating wait time for the first request that triggers revalidation. +products: + - cache +date: 2026-02-24 +--- + +Cloudflare's [`stale-while-revalidate`](/cache/concepts/cache-control/#stale-while-revalidate) support is now fully asynchronous. Revalidation begins at expiry rather than waiting for the next visitor request. Stale content is served immediately while Cloudflare refreshes the asset in the background, and no visitor has to wait for an origin round-trip. + +`stale-while-revalidate` is a Cache-Control directive that allows Cloudflare to serve an expired cached asset while a fresh copy is fetched from the origin. + +Asynchronous revalidation brings: + +- **Lower latency**: The first visitor is no longer blocked while the asset is updated from the origin, providing a faster experience. +- **Fresher content**: Assets are revalidated sooner, and visitors are more likely to receive up-to-date content. + +Note that your origin may see an increase in traffic due to revalidation on expiry. In addition, all revalidation cache statuses are now UPDATING or HIT instead of MISS or REVALIDATED. + +## Availability + +This change is live for all Free, Pro, and Business zones. Approximately 75% of Enterprise zones have been migrated, with the remaining zones rolling out throughout the quarter. + +## Get started + +To use this feature, make sure your origin includes the `stale-while-revalidate` directive in the `Cache-Control` header. Refer to the [Cache-Control documentation](/cache/concepts/cache-control/#stale-while-revalidate) for details. From bb60cbccc2850c1f8cf2e4a059e24fd94b8b1ade Mon Sep 17 00:00:00 2001 From: Tim Kornhammar Date: Wed, 25 Feb 2026 09:45:43 -0600 Subject: [PATCH 2/6] Update src/content/changelog/cache/2026-02-24-async-stale-while-revalidate.mdx Co-authored-by: ask-bonk[bot] <249159057+ask-bonk[bot]@users.noreply.github.com> --- .../changelog/cache/2026-02-24-async-stale-while-revalidate.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/changelog/cache/2026-02-24-async-stale-while-revalidate.mdx b/src/content/changelog/cache/2026-02-24-async-stale-while-revalidate.mdx index 5165751e3dbdeef..4e8610f270ee7a3 100644 --- a/src/content/changelog/cache/2026-02-24-async-stale-while-revalidate.mdx +++ b/src/content/changelog/cache/2026-02-24-async-stale-while-revalidate.mdx @@ -6,7 +6,7 @@ products: date: 2026-02-24 --- -Cloudflare's [`stale-while-revalidate`](/cache/concepts/cache-control/#stale-while-revalidate) support is now fully asynchronous. Revalidation begins at expiry rather than waiting for the next visitor request. Stale content is served immediately while Cloudflare refreshes the asset in the background, and no visitor has to wait for an origin round-trip. +Cloudflare's [`stale-while-revalidate`](/cache/concepts/cache-control/#revalidation) support is now fully asynchronous. Revalidation begins at expiry rather than waiting for the next visitor request. Stale content is served immediately while Cloudflare refreshes the asset in the background, and no visitor has to wait for an origin round-trip. `stale-while-revalidate` is a Cache-Control directive that allows Cloudflare to serve an expired cached asset while a fresh copy is fetched from the origin. From 5e58892da214e435a406b77e99f51ae6c4767964 Mon Sep 17 00:00:00 2001 From: Tim Kornhammar Date: Wed, 25 Feb 2026 09:46:04 -0600 Subject: [PATCH 3/6] Update src/content/changelog/cache/2026-02-24-async-stale-while-revalidate.mdx Co-authored-by: ask-bonk[bot] <249159057+ask-bonk[bot]@users.noreply.github.com> --- .../changelog/cache/2026-02-24-async-stale-while-revalidate.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/changelog/cache/2026-02-24-async-stale-while-revalidate.mdx b/src/content/changelog/cache/2026-02-24-async-stale-while-revalidate.mdx index 4e8610f270ee7a3..0d2e5b26b9b145c 100644 --- a/src/content/changelog/cache/2026-02-24-async-stale-while-revalidate.mdx +++ b/src/content/changelog/cache/2026-02-24-async-stale-while-revalidate.mdx @@ -15,7 +15,7 @@ Asynchronous revalidation brings: - **Lower latency**: The first visitor is no longer blocked while the asset is updated from the origin, providing a faster experience. - **Fresher content**: Assets are revalidated sooner, and visitors are more likely to receive up-to-date content. -Note that your origin may see an increase in traffic due to revalidation on expiry. In addition, all revalidation cache statuses are now UPDATING or HIT instead of MISS or REVALIDATED. +Note that your origin may see an increase in traffic due to revalidation on expiry. In addition, all revalidation cache statuses are now `UPDATING` or `HIT` instead of `MISS` or `REVALIDATED`. ## Availability From 954ac69db2fb68df08abd8d975cedbf1109f5b22 Mon Sep 17 00:00:00 2001 From: Tim Kornhammar Date: Wed, 25 Feb 2026 09:46:17 -0600 Subject: [PATCH 4/6] Update src/content/changelog/cache/2026-02-24-async-stale-while-revalidate.mdx Co-authored-by: ask-bonk[bot] <249159057+ask-bonk[bot]@users.noreply.github.com> --- .../changelog/cache/2026-02-24-async-stale-while-revalidate.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/changelog/cache/2026-02-24-async-stale-while-revalidate.mdx b/src/content/changelog/cache/2026-02-24-async-stale-while-revalidate.mdx index 0d2e5b26b9b145c..801f33cbd98fc57 100644 --- a/src/content/changelog/cache/2026-02-24-async-stale-while-revalidate.mdx +++ b/src/content/changelog/cache/2026-02-24-async-stale-while-revalidate.mdx @@ -23,4 +23,4 @@ This change is live for all Free, Pro, and Business zones. Approximately 75% of ## Get started -To use this feature, make sure your origin includes the `stale-while-revalidate` directive in the `Cache-Control` header. Refer to the [Cache-Control documentation](/cache/concepts/cache-control/#stale-while-revalidate) for details. +To use this feature, make sure your origin includes the `stale-while-revalidate` directive in the `Cache-Control` header. Refer to the [Cache-Control documentation](/cache/concepts/cache-control/#revalidation) for details. From a1649f41ed319cc56e9c099bdeed727973a1df9e Mon Sep 17 00:00:00 2001 From: Tim Kornhammar Date: Wed, 25 Feb 2026 10:25:47 -0600 Subject: [PATCH 5/6] Docs: Update revalidation, cache-control, and default-cache-behavior for async SWR --- .../docs/cache/concepts/cache-control.mdx | 6 ++-- .../cache/concepts/default-cache-behavior.mdx | 8 ++++- .../docs/cache/concepts/revalidation.mdx | 32 +++++++++++++------ 3 files changed, 31 insertions(+), 15 deletions(-) diff --git a/src/content/docs/cache/concepts/cache-control.mdx b/src/content/docs/cache/concepts/cache-control.mdx index b2734e95698671c..cfc15464490c5f0 100644 --- a/src/content/docs/cache/concepts/cache-control.mdx +++ b/src/content/docs/cache/concepts/cache-control.mdx @@ -79,11 +79,9 @@ Revalidation determines how the cache should behave when a resource expires, and * `stale-while-revalidate=` — When present in an HTTP response, indicates caches may serve the response in which it appears after it becomes stale, up to the indicated number of seconds since the resource expired. If [Always Online](/cache/how-to/always-online/) is enabled, then the `stale-while-revalidate` and `stale-if-error` directives are ignored. This directive is not supported when using the Cache API methods `cache.match` or `cache.put`. For more information, refer to the [Workers documentation for Cache API](/workers/runtime-apis/cache/#methods). :::note -Currently, `stale-while-revalidate` blocks on the first request that hits a stale cache item in the cache location, when the origin returns a response it will be served to this client with a MISS or REVALIDATED status. +`stale-while-revalidate` is now fully asynchronous. Revalidation begins at expiry rather than on the next visitor request. All requests during revalidation are served from cache with an UPDATING or HIT status. No request is blocked waiting for the origin. -Any other requests that arrive while this is happening in the same cache location for the same cached item will be served stale with the UPDATING status. - -For more details on this, refer to example 1 of our [Revalidation and request collapsing](/cache/concepts/revalidation/#example-1) guide. +For more details, refer to [Revalidation](/cache/concepts/revalidation/#asynchronous-revalidation). ::: * `stale-if-error=` — Indicates that when an error is encountered, a cached stale response may be used to satisfy the request, regardless of other freshness information. To avoid this behavior, include `stale-if-error=0` directive with the object returned from the origin. This directive is not supported when using the Cache API methods `cache.match` or `cache.put`. For more information, refer to the [Workers documentation for Cache API](/workers/runtime-apis/cache/#methods). diff --git a/src/content/docs/cache/concepts/default-cache-behavior.mdx b/src/content/docs/cache/concepts/default-cache-behavior.mdx index e12684640f25965..a6cb30cd9d19d20 100644 --- a/src/content/docs/cache/concepts/default-cache-behavior.mdx +++ b/src/content/docs/cache/concepts/default-cache-behavior.mdx @@ -7,7 +7,7 @@ head: --- -import { FeatureTable, Render, DashButton } from "~/components" +import { FeatureTable, GlossaryTooltip, Render, DashButton } from "~/components" Cloudflare respects the origin web server’s cache headers in the following order unless an [Edge Cache TTL cache rule](/cache/how-to/cache-rules/settings/#edge-ttl) overrides the headers. Refer to the [Edge TTL](/cache/how-to/configure-cache-status-code/#edge-ttl) section for details on default TTL behavior. @@ -36,6 +36,12 @@ Clients can send range requests to be served from the cache using the `Range` he - If the origin response includes a `Content-Length` header, then the specified byte range will be returned with an [HTTP 206](/support/troubleshooting/http-status-codes/2xx-success/#206-partial-content) response. - If the origin response does not include the `Content-Length` header, the cache will return the full content with an HTTP 200 response. +## Request collapsing + +When multiple requests arrive simultaneously at a single Cloudflare data center for the same asset that is not in cache (a cache miss), Cloudflare uses a cache lock to avoid sending duplicate requests to your origin. Only the first request is forwarded to the origin to fetch the asset. The remaining requests wait for the first request to complete, after which the response is [streamed](https://blog.cloudflare.com/introducing-concurrent-streaming-acceleration/) to all waiting requests. + +The cache lock ensures that Cloudflare only sends one request at a time to the origin for a given asset from a single location in Cloudflare's network, preventing the origin from receiving excessive traffic. + ## Default cached file extensions Cloudflare only caches based on file extension and not by MIME type. The Cloudflare CDN does not cache HTML or JSON by default. Additionally, by default Cloudflare caches a website's robots.txt. diff --git a/src/content/docs/cache/concepts/revalidation.mdx b/src/content/docs/cache/concepts/revalidation.mdx index c5c6c066f163909..aa01281ca4ea62e 100644 --- a/src/content/docs/cache/concepts/revalidation.mdx +++ b/src/content/docs/cache/concepts/revalidation.mdx @@ -1,26 +1,38 @@ --- -title: Revalidation and request collapsing +title: Revalidation pcx_content_type: concept --- -import { GlossaryTooltip } from "~/components" +## Stale-while-revalidate -Revalidation is a caching mechanism that checks the [freshness](/cache/concepts/retention-vs-freshness/#freshness-ttl) of cached data before serving it to users. If a cached object is no longer fresh and Cloudflare receives a request for it, the system makes a request to the origin to revalidate the object in the Cloudflare cache. By using headers like `If-Modified-Since` and `ETag`, Cloudflare validates content without fully re-fetching it. When these headers are missing, [Smart Edge Revalidation](https://blog.cloudflare.com/introducing-smart-edge-revalidation/) generates a `Last-Modified` header, ensuring efficient updates and delivery of fresh content while reducing origin traffic. +When a cached asset expires, Cloudflare uses the [`stale-while-revalidate`](/cache/concepts/cache-control/#revalidation) directive in `Cache-Control` to determine whether it can continue serving the stale asset while fetching a fresh copy from the origin. If the directive is present and the asset is within the allowed staleness window, Cloudflare serves the expired content to visitors and revalidates in the background. By using headers like `If-Modified-Since` and `ETag`, Cloudflare validates content without fully re-fetching it, reducing origin traffic. -## Revalidation towards origin +:::note +Asynchronous `stale-while-revalidate` is live for all Free, Pro, and Business zones. Enterprise zones are actively being migrated. +::: -For stale (expired TTL) content, Cloudflare will send a revalidation request to the origin. If the stale content is still valid Cloudflare will set a new TTL. If the content is expired, then the origin will provide new fresh content to replace the old. +## Asynchronous revalidation -Consider the following example scenarios. +Revalidation is fully asynchronous. When a cached asset reaches its TTL expiry and `stale-while-revalidate` is set, Cloudflare begins revalidating the asset with the origin immediately at expiry rather than waiting for the next visitor request. All visitor requests that arrive during revalidation are served from cache with a [HIT](/cache/concepts/cache-responses/#hit) or [UPDATING](/cache/concepts/cache-responses/#updating) status. No request is blocked waiting for the origin to respond. -### Example 1 +If the stale content is still valid, Cloudflare sets a new TTL. If the content has changed, the origin provides fresh content to replace the old. -One-thousand (1,000) requests arrive simultaneously at Cloudflare's network, and the requested resource was in Cloudflare but cannot be served because its TTL configuration indicates it is no longer fresh. This means that the resource needs to be served from the origin server. In this case, one request will go to the origin to be revalidated, while the other 999 requests will be served from cache with the status of [UPDATING](/cache/concepts/cache-responses/#updating). This means that the resource, although expired, is served stale from Cloudflare's cache, while the origin server is updating it. This behavior is defined by the [`stale-while-revalidate`](/cache/concepts/cache-control/#revalidation) directive in `cache-control`. If you do not wish to serve stale content, set the directive to zero seconds, `stale-while-revalidate=0`. +Note that your origin may see an increase in revalidation traffic because revalidation now starts at expiry rather than on the next request. -### Example 2 +## Synchronous revalidation (legacy) -One-thousand (1,000) requests arrive simultaneously at a single Cloudflare data center, and the requested asset is not in Cloudflare's cache (a cache miss). These requests will use a cache lock to communicate with your origin. This means that only the first request will go to origin to fetch the asset. The remaining 999 requests wait for the first request to fetch the data, after which the response is [streamed](https://blog.cloudflare.com/introducing-concurrent-streaming-acceleration/) to all the waiting requests. The cache lock ensures that Cloudflare only sends the origin one request at a time for a given asset from a location in Cloudflare's network, preventing the origin from getting too much traffic. +Previously, `stale-while-revalidate` blocked on the first request that arrived after a cached asset expired. That first request was held until the origin responded, and was served with a [MISS](/cache/concepts/cache-responses/#miss) or [REVALIDATED](/cache/concepts/cache-responses/#revalidated) status. Any other requests that arrived during this time for the same asset in the same cache location were served stale with the [UPDATING](/cache/concepts/cache-responses/#updating) status. + +For example, if 1,000 requests arrived simultaneously for an expired asset, one request would go to the origin while the other 999 were served stale from cache. The first visitor experienced higher latency because they had to wait for the origin round-trip. + +With asynchronous revalidation, all 1,000 requests are served from cache immediately and no visitor is blocked. + +## Controlling stale behavior + +Cloudflare only serves stale content during revalidation if your origin includes the `stale-while-revalidate` directive in its `Cache-Control` header. Without this directive, visitors wait for the origin to respond before receiving content. + +If your origin sets `stale-while-revalidate` but you want to override it, you can disable stale serving through the [Serve stale content while revalidating](/cache/how-to/cache-rules/settings/#serve-stale-content-while-revalidating) setting in Cache Rules. Directives like `must-revalidate` and `no-cache` also prevent stale content from being served when [Origin Cache Control](/cache/concepts/cache-control/#enable-origin-cache-control) is enabled. For all available options, refer to [Cache-Control directives](/cache/concepts/cache-control/#cache-control-directives). ## Smart revalidation towards users From 17c8c237a34fc2f8392f14a0322f7d4a990742b8 Mon Sep 17 00:00:00 2001 From: Pedro Sousa <680496+pedrosousa@users.noreply.github.com> Date: Thu, 26 Feb 2026 10:06:30 +0000 Subject: [PATCH 6/6] Apply suggestions from PCX review --- src/content/docs/cache/concepts/cache-control.mdx | 2 +- src/content/docs/cache/concepts/revalidation.mdx | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/content/docs/cache/concepts/cache-control.mdx b/src/content/docs/cache/concepts/cache-control.mdx index cfc15464490c5f0..98ecfa374d2181a 100644 --- a/src/content/docs/cache/concepts/cache-control.mdx +++ b/src/content/docs/cache/concepts/cache-control.mdx @@ -79,7 +79,7 @@ Revalidation determines how the cache should behave when a resource expires, and * `stale-while-revalidate=` — When present in an HTTP response, indicates caches may serve the response in which it appears after it becomes stale, up to the indicated number of seconds since the resource expired. If [Always Online](/cache/how-to/always-online/) is enabled, then the `stale-while-revalidate` and `stale-if-error` directives are ignored. This directive is not supported when using the Cache API methods `cache.match` or `cache.put`. For more information, refer to the [Workers documentation for Cache API](/workers/runtime-apis/cache/#methods). :::note -`stale-while-revalidate` is now fully asynchronous. Revalidation begins at expiry rather than on the next visitor request. All requests during revalidation are served from cache with an UPDATING or HIT status. No request is blocked waiting for the origin. +`stale-while-revalidate` is fully asynchronous. Revalidation begins at expiry rather than on the next visitor request. All requests during revalidation are served from cache with an UPDATING or HIT status. No request is blocked waiting for the origin. For more details, refer to [Revalidation](/cache/concepts/revalidation/#asynchronous-revalidation). ::: diff --git a/src/content/docs/cache/concepts/revalidation.mdx b/src/content/docs/cache/concepts/revalidation.mdx index aa01281ca4ea62e..346f20882155fc2 100644 --- a/src/content/docs/cache/concepts/revalidation.mdx +++ b/src/content/docs/cache/concepts/revalidation.mdx @@ -9,7 +9,7 @@ pcx_content_type: concept When a cached asset expires, Cloudflare uses the [`stale-while-revalidate`](/cache/concepts/cache-control/#revalidation) directive in `Cache-Control` to determine whether it can continue serving the stale asset while fetching a fresh copy from the origin. If the directive is present and the asset is within the allowed staleness window, Cloudflare serves the expired content to visitors and revalidates in the background. By using headers like `If-Modified-Since` and `ETag`, Cloudflare validates content without fully re-fetching it, reducing origin traffic. :::note -Asynchronous `stale-while-revalidate` is live for all Free, Pro, and Business zones. Enterprise zones are actively being migrated. +Asynchronous `stale-while-revalidate` is live for all Free, Pro, and Business zones. Enterprise zones are actively being migrated. The previous synchronous behavior is described in [Synchronous revalidation](#synchronous-revalidation-legacy). ::: ## Asynchronous revalidation @@ -22,11 +22,15 @@ Note that your origin may see an increase in revalidation traffic because revali ## Synchronous revalidation (legacy) -Previously, `stale-while-revalidate` blocked on the first request that arrived after a cached asset expired. That first request was held until the origin responded, and was served with a [MISS](/cache/concepts/cache-responses/#miss) or [REVALIDATED](/cache/concepts/cache-responses/#revalidated) status. Any other requests that arrived during this time for the same asset in the same cache location were served stale with the [UPDATING](/cache/concepts/cache-responses/#updating) status. +:::note +Synchronous revalidation refers to a previous implementation that is only available to a subset of Enterprise zones that have not been migrated yet. All other zones use [asynchronous revalidation](#asynchronous-revalidation). +::: + +With synchronous revalidation (a legacy implementation), `stale-while-revalidate` blocks on the first request that arrives after a cached asset expired. That first request is held until the origin responds, and is served with a [MISS](/cache/concepts/cache-responses/#miss) or [REVALIDATED](/cache/concepts/cache-responses/#revalidated) status. Any other requests that arrive during this time for the same asset in the same cache location are served stale with the [UPDATING](/cache/concepts/cache-responses/#updating) status. -For example, if 1,000 requests arrived simultaneously for an expired asset, one request would go to the origin while the other 999 were served stale from cache. The first visitor experienced higher latency because they had to wait for the origin round-trip. +For example, if 1,000 requests arrive simultaneously for an expired asset in this previous implementation, one request goes to the origin while the other 999 are served stale from cache. The first visitor experiences higher latency because they have to wait for the origin round-trip. -With asynchronous revalidation, all 1,000 requests are served from cache immediately and no visitor is blocked. +On the other hand, with [asynchronous revalidation](#asynchronous-revalidation) all 1,000 requests are served from cache immediately and no visitor is blocked. ## Controlling stale behavior