Shaduf.
HTTP Cache Field Guide/Cloudflare Cache Rules and Origin Cache Control

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.

Documentation-only. Sources were retrieved 20 Sep 2026, 10:26:19–10:31:29 UTC. No Cloudflare account, zone, authorized endpoint, response capture, or purge request was available; no live Cloudflare result is claimed.

New research · 20 Sep 2026

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.

Open the reader-facing Cloudflare guide page →

Five separate questions in a Cloudflare cache decision An origin response supplies cache directives. Cloudflare edge policy decides whether those directives are respected or overridden. A cache key decides object identity, a viewer policy controls browser-facing headers, and a purge selects stored objects. These are separate evidence questions. Origin intent Cache-ControlExpires public · privateno-store Edge policy OCC + Edge Cache TTL respect · bypass · override hidden edge lifetime Cache key URL + selected variants identity, not freshness Viewer Browser TTL max-age in response not edge proof Purge scope URL · tag · prefix · host · all targets stored objects, not browsers
Keep the axes separate: a viewer 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

  1. Origin: for shared HTTP freshness, s-maxage wins over max-age, which wins over Expires; no-cache permits storage only with validation, while no-store and private constrain shared storage.
  2. 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.
  3. 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.
  4. 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 signalEdge resultViewer / browserKey and purgeEvidence boundary
public, s-maxage=60, max-age=300With 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-maxagemax-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 ExpiresBypass-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=0OCC 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 AuthorizationNormal 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-09Tag 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

  1. Keep the path out of public Cache Rules, or use a rule that respects origin control and bypasses when no header is supplied.
  2. Return a deliberate policy such as private, no-store when shared or intentional HTTP-cache retention is unacceptable; use private, no-cache when browser retention with validation is acceptable.
  3. 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

  1. Use a new fingerprinted URL for changed bytes and an explicit public policy when the representation is safe to share.
  2. Configure Edge TTL to respect origin or document the reason for an override; record Browser TTL separately.
  3. Keep query strings in the key unless they are proven irrelevant. Use a deployment Cache-Tag for a known release and choose exact URL, tag, prefix, hostname, or everything only for the required blast radius.
  4. 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.

AxisCloudFront auditCloudflare caseDo not generalize
Origin intentOrigin 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 lifetimeEffective 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 lifetimeViewer-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 keyCache-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.
InvalidationPath 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.
EvidenceNamed 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 with Cache-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.

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.

Search published pools, pages, reports, and evidence.