Dated report · Cloudflare-specific · 20 Sep 2026
Cloudflare Cache Rules and Origin Cache Control
A documentation-grounded case for separating origin intent, Cloudflare edge policy, browser freshness, cache-key identity, and purge scope.
The short answer
Cloudflare does not reduce to one Cache-Control header. First decide whether the representation is safe for shared storage. Then read the zone's Origin Cache Control (OCC) state and matching Cache Rule: its Edge Cache TTL can respect, bypass by default, or override origin signals. Browser TTL is a separate viewer policy. The cache key decides which variants share an object; purge scope decides which stored objects are invalidated.
Safe operating rule: keep private responses out of public rules; use explicit browser and shared lifetimes for safe public content; inspect the effective custom key before purging; and treat a purge API success as request acceptance, not an eviction receipt.
Cache-Control value does not reveal the hidden Edge Cache TTL, and a purge does not erase a browser or service-worker copy.Precedence by concern
- Origin: for shared HTTP freshness,
s-maxagewins overmax-age, which wins overExpires;no-cachepermits storage only with validation, whileno-storeandprivateconstrain shared storage. - Cloudflare edge: OCC and the matching Cache Rule determine whether that origin signal is respected, bypassed by default, or overridden. An explicit Edge or status-code TTL can change edge eligibility and lifetime.
- Viewer: Browser TTL and the delivered browser-facing header are downstream controls. A purge of Cloudflare's edge objects does not clear a visitor's browser cache.
- Identity and purge: the cache key decides which variants are the same object. Select a purge scope from that key and the intended blast radius; verify with a later fetch and named response evidence.
One-page precedence and purge matrix
“Edge result” is the documented outcome for the stated OCC/Cache Rule mode, not a live result from a named zone. Labels: [N] HTTP/RFC norm, [D] Cloudflare documentation, [I] inference, [R] recommendation, [U] unknown without a zone test.
| Origin signal | Edge result | Viewer / browser | Key and purge | Evidence boundary |
|---|---|---|---|---|
| public, s-maxage=60, max-age=300 | With OCC on and Edge TTL respecting origin, shared freshness is 60 seconds; an explicit override can replace it. [N][D] | max-age=300 is the browser intent when Browser TTL respects existing headers; a Browser TTL rule may alter it. [D] | Exact URL purge targets the matching key representation; tag, prefix, or host scopes are broader. [D] | Capture the zone rule, key, CF-Cache-Status, and Age. A 200 purge response is not eviction proof. [U] |
| public, max-age=300; no s-maxage | max-age wins over Expires for the HTTP baseline; an Edge/status override can differ. [N][D] | Viewer max-age=300 unless Browser TTL changes it. [D] | Default query-inclusive identity differs from a custom key that ignores query strings; record exact inputs before a URL purge. [D][I] | A fresh browser response can survive an edge purge. Repeat from a controlled client. [U] |
| No Cache-Control and no Expires | Bypass-by-default bypasses; the respect-origin/default mode uses Cloudflare's documented status defaults when eligible. A matching explicit Edge TTL changes the result. [D] | No origin freshness signal; Browser TTL/default behavior is configuration-dependent. [D][U] | Header absence does not remove key dimensions. Capture status, key settings, CF-Cache-Status, and Age. [D][U] | Default TTL documentation is not a response capture or proof of residency in a POP. [U] |
| no-cache or max-age=0 | OCC on documents cache-and-revalidate; OCC off documents non-cache behavior. An explicit Edge override can cache and disable revalidation directives at the edge. [D] | Without Browser TTL override, the origin's validation intent remains relevant to the client. [N][D] | Revalidation does not change object identity. Purge still targets edge copies only. [N][D] | REVALIDATED or EXPIRED would be live evidence only if captured from the named path. [U] |
| no-store, private, Set-Cookie, or Authorization | Normal OCC behavior blocks shared storage, with documented rule/product exceptions. Treat a public override as a privacy review blocker. [N][D][R] | Preserve restrictive viewer policy for sensitive bodies; a viewer override can change downstream storage intent. [N][R] | Never treat a custom key as a privacy guarantee. Prefer no shared storage; if an object was intentionally stored, purge with the exact key or deliberate broad scope. [R][U] | No purge can prove that a browser, service worker, or intermediary never retained an earlier response. [S][U] |
| Cache-Tag: release-2026-09 | Tag labels the object for invalidation; TTL and key still come from the other controls. Cloudflare strips the tag before visitor/Worker delivery. [D] | No visitor-facing Cache-Tag should be expected. [D] | Tag purge invalidates every object carrying that tag; prefix/host/everything have different blast radii. [D] | A successful purge request acknowledges receipt; follow with a controlled fetch. No purge ran here. [D][U] |
Two decision paths
A · Private or sensitive response
- Keep the path out of public Cache Rules, or use a rule that respects origin control and bypasses when no header is supplied.
- Return a deliberate policy such as
private, no-storewhen shared or intentional HTTP-cache retention is unacceptable; useprivate, no-cachewhen browser retention with validation is acceptable. - Audit OCC, every matching rule, Workers/Cache API, custom key, and downstream copies. Do not use an after-the-fact purge as a privacy fix.
What remains unproven: this run has no zone configuration, response, or downstream capture.
B · Public, versioned asset
- Use a new fingerprinted URL for changed bytes and an explicit public policy when the representation is safe to share.
- Configure Edge TTL to respect origin or document the reason for an override; record Browser TTL separately.
- Keep query strings in the key unless they are proven irrelevant. Use a deployment
Cache-Tagfor a known release and choose exact URL, tag, prefix, hostname, or everything only for the required blast radius. - After an authorized purge, fetch the same URL from a named vantage and record status,
CF-Cache-Status,Age,CF-Ray, headers, and time.
Boundary: a new URL proves a different target, not deletion of the old URL everywhere.
Matched CloudFront crosswalk
This comparison stays on the same axes as the CloudFront TTL and invalidation audit; it is not a second CloudFront tutorial.
| Axis | CloudFront audit | Cloudflare case | Do not generalize |
|---|---|---|---|
| Origin intent | Origin headers are interpreted alongside the selected cache policy and its TTL bounds. | OCC documents product-specific handling of no-cache, zero lifetimes, auth, cookies, and revalidation. | Cloudflare OCC is not an RFC-only conclusion and does not mean every Edge Rule respects the header. |
| Edge lifetime | Effective MinTTL/DefaultTTL/MaxTTL bound the nominal CloudFront edge result. | Cache Rule Edge TTL has respect, bypass-by-default, and override modes; hidden edge TTL is not a viewer header. | A viewer Cache-Control value cannot be used as either provider's full edge policy. |
| Viewer lifetime | Viewer-facing headers are separate from CloudFront object caching. | Browser TTL is separate from Edge TTL; purge does not clear browser copies. | Provider behavior around a higher origin max-age is not interchangeable. |
| Cache key | Cache-policy dimensions determine which variants share an object. | Default and custom keys select URL/query/header/cookie/other dimensions subject to plan and request limits. | Names, defaults, plan gates, and purge matching rules are provider-specific. |
| Invalidation | Path invalidation follows CloudFront path and effective-key rules; operation status is polled to Completed. | URL, tag, prefix, hostname, and everything scopes have distinct Cloudflare semantics; custom key inputs can affect URL purge. | No CloudFront completion implies a Cloudflare eviction, or vice versa. |
| Evidence | Named distribution configuration, response capture, and invalidation status are required for product claims. | Record Trace/config, response headers, CF-Cache-Status, Age, CF-Ray, and authorized purge response. | This report has none of those Cloudflare observations. |
Authorized-only verification template
Use only with explicit authorization. Replace placeholders and redact tokens, cookies, personal data, zone IDs, and secrets before saving results. This template is a plan, not an executed test.
- Record configuration: hostname, plan, OCC state, proxied DNS, matching rule/expression, Edge TTL mode/value, status-code TTL, Browser TTL mode/value, custom-key dimensions, Trace result, and Workers/Response Rules/Transform/Tiered Cache products.
- Record origin fixtures: synthetic responses for
s-maxage=60, max-age=300;max-age=300; absent freshness headers;no-cache;no-store;private; a permitted Authorization/Set-Cookie case; and a versioned response withCache-Tag. - Capture the same URL twice: use an authorized URL and a stable vantage; do not add a random query parameter unless query variation is the subject of the test.
curl -sS -D /tmp/cloudflare.headers -o /dev/null \
-H 'Accept: */*' \
https://AUTHORIZED-ZONE.example/assets/app.20260920.js
Record status, Cache-Control, Expires, Age, CF-Cache-Status, CF-Ray, ETag, Last-Modified, Vary, Set-Cookie, Cache-Tag if present, request method, time, POP/vantage, and whether the client was warm or cold. Compare origin headers with client-facing headers; do not use a viewer header as a proxy for hidden Edge TTL.
- Test purge only if authorized: write down the intended scope and exact key inputs first. For a custom key, include documented header/cookie/query inputs in an API URL purge; for tag/prefix/host/everything, record the broader collateral scope.
- Verify after purge: record the API status/body, then fetch again and record
CF-Cache-Status,Age,CF-Ray, body marker/hash, and time. A 200 acknowledges the request; it does not prove object existence, eviction from every tier, or deletion downstream.
This can prove
- The identified zone's rule/OCC/key state at the time of the read.
- The response and Cloudflare status observed from one named path and vantage.
- Whether the tested fixture followed the documented intended result.
- That Cloudflare accepted a purge request and what the follow-up path reported.
This cannot prove
- Global absence from every POP, tier, origin-connected cache, browser, service worker, or proxy.
- Behavior for untested methods, hosts, paths, variants, status codes, plans, or products.
- That a 200 purge response evicted a particular object.
- That a response header reveals hidden Edge TTL or proves privacy for every tenant variant.
Sources and retrieval note
Cloudflare pages below are the primary product sources; RFC pages are the normative baseline. All listed vendor and standards sources were retrieved during 20 Sep 2026 10:26:19–10:31:29 UTC. Product settings and plan limits can change; recheck the live documentation and the named zone before making an operational claim.
Cloudflare documentation
- Cache Rules overview
- Cache Rules settings
- Origin Cache Control
- Edge and Browser Cache TTL · Set Browser TTL
- Default cache behavior · Cache responses
- Cache Keys · Revalidation
- Purge cache overview · Purge by single file · Purge by cache key
- Purge by tags · Purge by prefix · Purge by hostname · Purge everything
- Purge API · CDN-Cache-Control boundary · Cache Response Rules boundary
Normative and supporting references
What remains uncertain
This report is a narrow, documentation-only model. The actual plan, proxied hostname, OCC state, Cache Rule ordering, status-code TTL, Browser TTL, custom key, origin fixture, POP, response headers, CF-Cache-Status, Age, CF-Ray, and purge authorization were not supplied. Cloudflare's generic and OCC-specific descriptions of no-cache also need a controlled, authorized fixture to resolve for a named zone. Workers, response rules, CDN-Cache-Control, transform rules, tiered caches, service workers, browsers, and corporate proxies can change the practical result. No Cloudflare measurement or purge was executed.