Our services sit behind Cloudflare. A single zone-wide Cache Rule makes edge caching fully origin-driven: Cloudflare never decides on its own what to cache — each service opts in per-response using standard HTTP caching headers.
This document explains how the rule works, how to opt an endpoint in or out, and what happens behind the edge.
One rule per Cloudflare zone:
Setting | Value |
|---|---|
When incoming requests match | (http.host wildcard r"*") — every host in the zone |
Cache eligibility | Eligible for cache |
Edge TTL | Use cache-control header if present, bypass cache if not |
Browser TTL | Respect origin TTL |
The key part is the Edge TTL mode: a response is cached only when the origin explicitly sends a Cache-Control header that allows it. Anything else is proxied through untouched — exactly as if the rule did not exist.
Cache Rules are configured per zone. When a new domain (zone) is added, the same rule must be created there once.
Origin response | Edge behavior |
|---|---|
Cache-Control: public, max-age=172800 | ✅ cached for 172800 s |
Cache-Control: s-maxage=600, max-age=60 | ✅ edge caches for 600 s ( s-maxage wins at the edge), browsers get 60 s |
Cache-Control: private, no-store, no-cache, or max-age=0 | ❌ not cached |
No Cache-Control header at all | ❌ not cached (the "bypass if not present" part) |
Response carries Set-Cookie | ❌ not cached, even if public, max-age is also present |
So the precise contract is: a response is edge-cached iff all three hold:
Normally, your framework attaches a session cookie (Set-Cookie) to regular HTML responses, which disqualifies them from edge caching automatically — even if a middleware adds public, max-age. Personalized content can never leak into the shared cache by accident.
The flip side: if you want a page cached at the edge, you must make sure it is served without Set-Cookie and with an explicit public, max-age.
From any service, in any language — send the right headers:
and make sure the response has no Set-Cookie. That's it; no Cloudflare configuration is needed.
To use different TTLs for the edge and for browsers:
or, Cloudflare-specific (takes precedence over Cache-Control at the edge and is invisible to other proxies):
Do nothing — that is the default. Responses without Cache-Control bypass the edge cache. To be explicit (e.g. for an API that must never be cached anywhere):
While an entry lives at the edge, the origin cannot update it — lowering max-age only affects future entries. To drop content immediately:
curlcf-cache-status | Meaning |
|---|---|
HIT | served from the edge cache |
MISS | cacheable, fetched from origin, now stored — repeat should be HIT |
EXPIRED | was cached, TTL ran out, revalidated against origin |
DYNAMIC | not eligible for caching (no allowing headers, or Set-Cookie) |
BYPASS | origin explicitly forbade caching ( no-store/private) |
Set-Cookie silently disables caching. A stray cookie (session started on an asset route, a debug middleware) turns HIT into DYNAMIC. Strip cookies on cacheable routes at the web-server level if in doubt.max-age also drives browsers. A long TTL means returning visitors keep stale content even after an edge purge. Split with s-maxage /CDN-Cache-Control when that matters.
Understanding Projects
Projects in Novps are the foundation of how your applications and resources are organized within the platform...
Pricing
Comparison table of tariff plans
Ownership and Access Control
Short description of project ownership and access control
How to create new Project
Step-by-step instructions describing the process of creating a new project