Cache-Status proxy response
Tells the client exactly what each cache in the chain did with the request — hit, miss, stale, expired, or bypassed.
What it does
Cache-Status tells the client exactly what every cache in the chain did with this request — hit, miss, stale, expired, or bypassed. Each intermediary cache appends its own status entry as the response travels back to the client.
It's the standardised replacement for the X-Cache header that CDNs have been using inconsistently for years. Cloudflare uses CF-Cache-Status: HIT, Fastly uses X-Cache: HIT, AWS CloudFront uses X-Cache: Hit from cloudfront — all doing the same thing with different names and formats. Cache-Status (RFC 9211, 2022) gives everyone a common format.
Syntax
Cache-Status: <cache-name>; <parameter>[; <parameter>]
Cache-Status: <cache1>; hit, <cache2>; fwd=miss
Each entry: a cache name (quoted string or token) followed by semicolon-separated parameters.
Examples:
Cache-Status: ExampleCDN; hit
Cache-Status: ExampleCDN; fwd=miss; stored
Cache-Status: ExampleCDN; hit; ttl=1800
Cache-Status: OriginCache; fwd=stale; fwd-status=200; stored, CDN; hit
Parameters
| Parameter | Meaning |
|---|---|
hit |
Cache served the response from its store |
fwd=<reason> |
Cache forwarded the request (didn't serve from cache) |
fwd-status=<code> |
HTTP status of the forwarded response |
stored |
Cache stored the response after forwarding |
collapsed |
Request was collapsed with another in-flight request |
ttl=<seconds> |
Time-to-live remaining when the response was served |
key=<string> |
Cache key used (for debugging) |
detail=<string> |
Implementation-specific detail string |
fwd values (why the cache forwarded)
fwd value |
Meaning |
|---|---|
miss |
Not in cache |
stale |
In cache but stale, revalidated |
request |
Request headers forced bypass (Cache-Control: no-cache) |
bypass |
Cache is configured to bypass for this request |
method |
Request method not cacheable |
vary |
Vary mismatch — no matching stored variant |
expired |
Cached copy expired |
Reading a multi-cache response
Cache-Status: OriginShield; fwd=miss; stored, EdgeCache; hit; ttl=3540
Reading right to left (last cache in chain first... actually left to right — first entry is the last to add):
EdgeCache; hit; ttl=3540— the edge CDN node served from cache, 3540 seconds TTL remainingOriginShield; fwd=miss; stored— the origin shield had a miss, fetched from origin, stored it
This tells you: edge cache HIT, origin shield was initially a MISS (cold cache or first request after TTL expired).
X-Cache vs Cache-Status
X-Cache is the old de facto standard — every CDN implemented it differently:
# Cloudflare
CF-Cache-Status: HIT
# Fastly
X-Cache: HIT
X-Cache-Hits: 3
# CloudFront
X-Cache: Hit from cloudfront
# Varnish
X-Cache: HIT
X-Varnish: 123456789 123456780
Cache-Status gives a unified format. Adoption is growing but X-Cache variants will persist for years. In 2026, check for both when debugging CDN caching issues.
Debugging with Cache-Status
# Check cache status on a response
curl -sI https://example.com/api/data | grep -i 'cache-status\|x-cache\|cf-cache\|age'
# Typical hit response:
# Cache-Status: Fastly; hit; ttl=3598
# Age: 2
# Typical miss response:
# Cache-Status: Fastly; fwd=miss; stored
# Age: 0
Real-world examples
Simple CDN hit:
HTTP/1.1 200 OK
Cache-Status: MyCDN; hit; ttl=86398
Age: 2
Cache-Control: public, max-age=86400
Miss that got stored:
HTTP/1.1 200 OK
Cache-Status: MyCDN; fwd=miss; stored
Age: 0
Cache-Control: public, max-age=3600
Stale response served while revalidating:
HTTP/1.1 200 OK
Cache-Status: MyCDN; hit; fwd=stale; ttl=-30
Age: 3630
Cache-Control: public, max-age=3600, stale-while-revalidate=3600
ttl=-30 means 30 seconds past expiry — being served stale within the stale-while-revalidate window.
Bypassed (client forced revalidation):
HTTP/1.1 200 OK
Cache-Status: MyCDN; fwd=request
Client sent Cache-Control: no-cache — CDN respected it and forwarded.
FAQ
Do all CDNs support Cache-Status?
Not yet — RFC 9211 was published in 2022. Fastly has added support. Others are adopting it. In 2026, you're more likely to encounter vendor-specific headers (CF-Cache-Status, X-Cache) than Cache-Status on most CDNs. Check your CDN's documentation. The standardisation effort is ongoing.
Should I implement Cache-Status on my own caching proxy?
If you're building or operating caching infrastructure, yes — it's the forward-looking standard. Application servers don't need to set it; only actual caches (CDNs, reverse proxies, Varnish, nginx proxy_cache) do.
Fun fact
The X-Cache header proliferation problem is a perfect example of what happens when infrastructure teams all solve the same problem independently without coordination. By 2020, there were at least 15 different X-Cache-style headers across major CDN and caching vendors, all meaning roughly the same thing but formatted differently — making cross-CDN debugging scripts impossible to write generically. RFC 9211 was a direct response to this chaos, driven by engineers who were tired of writing bespoke parsers for every CDN they worked with.