Decision tree logic for cache behavior and TTL expiration
Configure all cache parameters to evaluate freshness, retention, revalidation, stale behavior, and request collapsing across Origin, Edge, and Browser layers.
fetch(url, { cf: { cacheTtl: 3600 } }). Per-request override when using Cloudflare Workers.Cache-Control directives entirely for edge caching.max-age for CDN/proxy caches. Browsers ignore this directive.Cache-Control: no-storeCache-Control: privateCache-Control: max-age=0Set-Cookie header presentAuthorization headermust-revalidate, public, or s-maxage presentCache-Control: public, max-age>0Expires header (future date)max-age takes precedence if both sets-maxage directivemax-age for shared caches (CDN)Set-Cookie| Priority | Source | Affects | Behavior |
|---|---|---|---|
| 1 | Edge Cache TTL (Cache Rules) |
Cloudflare Edge | Overrides all origin headers for edge caching |
| 2 | Cloudflare-CDN-Cache-Control: max-age |
Cloudflare Edge only | Not proxied downstream |
| 3 | CDN-Cache-Control: max-age |
All CDNs | Proxied to downstream CDNs |
| 4 | Cache-Control: s-maxage |
Shared caches (CDN) | Overrides max-age for CDN, browsers ignore |
| 5 | Cache-Control: max-age |
All caches | Default TTL for browsers and CDN |
| 6 | Expires header |
All caches | Legacy. Ignored if max-age present |
| 7 | Cloudflare Default TTL | Cloudflare Edge | Based on status code when no headers present |
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β INCOMING REQUEST β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββ
β Is request method GET or HEAD? β
βββββββββββββββββββββββββββββββββββββββββ
β β
NO YES
β β
βΌ βΌ
βββββββββββββββ βββββββββββββββββββββββββββββββββββββββββ
β BYPASS β β Edge Cache TTL rule exists? β
β (DYNAMIC) β βββββββββββββββββββββββββββββββββββββββββ
βββββββββββββββ β β
YES NO
β β
βΌ βΌ
βββββββββββββββ βββββββββββββββββββββββββββββββββββββββββ
β Use Edge β β Cloudflare-CDN-Cache-Control exists? β
β Cache TTL β βββββββββββββββββββββββββββββββββββββββββ
βββββββββββββββ β β
YES NO
β β
βΌ βΌ
βββββββββββββββββββ βββββββββββββββββββββββββββββββββββββββββ
β Use Cloudflare- β β CDN-Cache-Control exists? β
β CDN-Cache-Ctrl β βββββββββββββββββββββββββββββββββββββββββ
βββββββββββββββββββ β β
YES NO
β β
βΌ βΌ
βββββββββββββββ βββββββββββββββββββββββββββββββββββββββββ
β Use CDN- β β Surrogate-Control exists? β
β Cache-Ctrl β βββββββββββββββββββββββββββββββββββββββββ
βββββββββββββββ β β
YES NO
β β
βΌ βΌ
βββββββββββββββ βββββββββββββββββββββββββββββββββββββββββ
β Ignore β β Check Cache-Control directive β
βCache-Controlβ βββββββββββββββββββββββββββββββββββββββββ
βββββββββββββββ β
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β CACHE-CONTROL EVALUATION β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β no-store β BYPASS (never cache) β
β private β BYPASS (browser only) β
β no-cache + OCC ON β CACHE + always revalidate β
β no-cache + OCC OFFβ BYPASS β
β max-age=0 + OCC ONβ CACHE + revalidate β
β max-age=0 + OCC OFFβ BYPASS β
β s-maxage > 0 β CACHE (use s-maxage for edge TTL) β
β max-age > 0 β CACHE (use max-age for TTL) β
β public β CACHE β
β No directive β Use default TTL based on status code β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
If-Modified-Since + Last-ModifiedIf-None-Match + ETagmust-revalidate - Must check origin when staleproxy-revalidate - CDN must revalidate (not browsers)stale-while-revalidate=<seconds>stale-if-error=<seconds>Cache-Control: max-age=14400, s-maxage=84000
Cloudflare-CDN-Cache-Control: max-age=24400
CDN-Cache-Control: max-age=18000
| Browser | 14,400s (4h) |
| Cloudflare Edge | 24,400s (6.8h) |
| Other CDNs | 18,000s (5h) |
| Shared Caches | 84,000s (23h) |
Cache-Control: stale-if-error=400
Cloudflare-CDN-Cache-Control: stale-if-error=60
CDN-Cache-Control: stale-if-error=200
| Browser/Origin | 400s stale on error |
| Cloudflare Edge | 60s stale on error |
| Other CDNs | 200s stale on error |
| Directive | OCC Disabled | OCC Enabled |
|---|---|---|
s-maxage=0 |
Will cache using default TTL | Will not cache |
max-age=0 |
Will not cache (BYPASS) | Cache + revalidate on each request |
no-cache |
MISS in logs | BYPASS in logs, always revalidate |
no-store |
Will not cache | Will not cache |
private |
Will cache (strips header) | Will not cache |
Authorization header |
Content may be cached | Only if must-revalidate, public, or s-maxage present |
Set-Cookie + default level |
Cache (strips Set-Cookie) | BYPASS (preserves Set-Cookie) |
| Use Case | Header Configuration |
|---|---|
| Cache static asset for 1 day | Cache-Control: public, max-age=86400 |
| Never cache sensitive data | Cache-Control: no-store |
| Browser only (no CDN cache) | Cache-Control: private, max-age=3600 |
| Cache but always revalidate | Cache-Control: public, no-cache |
| Different TTL for CDN vs Browser | Cache-Control: public, max-age=7200, s-maxage=3600 |
| Serve stale during revalidation | Cache-Control: max-age=600, stale-while-revalidate=30 |
| Serve stale on origin error | Cache-Control: public, max-age=3600, stale-if-error=60 |
| Cloudflare-specific TTL only | Cloudflare-CDN-Cache-Control: max-age=86400 |
Source: Cloudflare Cache Documentation | Generated from developers.cloudflare.com/cache/concepts/