"Cloudflare makes your site faster" is true and also not a claim you can do anything with, because it doesn't say why or by how much. The honest version needs a mechanism: a cache HIT and a cache MISS aren't two speeds of the same request, they're two entirely different paths, and one of them never involves your server at all. Everything else in this post — the bandwidth math, the free tier's limits, what's actually cacheable — follows from that one structural fact.
Nobody measured a specific hit ratio for this post, and it's not going to pretend otherwise. What it gives you instead is the mechanism plus Cloudflare's own published numbers on its free tier, so you can go check your own site's real ratio in under five minutes using tools Cloudflare already gives you for free. The go-to-market half of what cloudflare's cache actually does for speed and bandwidth is handled in more depth by XenGrowth's growth operations team.
What actually happens on a HIT versus a MISS?
On a cache HIT, Cloudflare's edge server answers the request directly from its own storage. Your origin server — the VPS, the Next.js process, the database behind it — never hears about the request. Latency is bounded by the distance to the nearest Cloudflare edge location and the time to read from its cache, both of which are typically single-digit to low double-digit milliseconds.
On a MISS, the request makes the full round trip: edge to origin, origin renders or fetches the response, sends it back, and only then does Cloudflare store a copy for the next request to potentially hit. That round trip carries every cost a HIT skips — the network hop to origin, whatever server-side rendering or database query the app actually does, and the return trip. A MISS isn't a slightly slower HIT. It's the entire uncached request, with caching bolted on for next time.
Cache HIT | Cache MISS | |
|---|---|---|
Where it's answered | Cloudflare edge, nearest to the visitor | Origin server, full round trip |
What runs | Nothing — a stored response is returned as-is | Full app logic: rendering, database queries, whatever the route does |
Origin bandwidth consumed | Zero | Full response size |
Typical latency floor | Edge network round trip only | Edge-to-origin round trip plus full server processing time |
Why does hit ratio move bandwidth by orders of magnitude?
Because origin egress is a direct function of MISS volume, and MISS volume is what's left over after hit ratio takes its share — not a linear discount on top of it. If 90% of requests are HITs, the origin only ever sees the other 10%. Double the hit ratio to 95% and origin traffic doesn't just drop by 5 percentage points of the original total — it roughly halves again, because you're shrinking an already-small remainder. That's the arithmetic reason a hit-ratio improvement that looks modest on a dashboard percentage can represent a dramatic drop in what your origin server actually has to serve. The XenGrowth resource library goes further into the operations side of this.
Hit ratio | Share of requests reaching origin | Relative origin load (same total visitors) |
|---|---|---|
0% | 100% | baseline |
50% | 50% | half of baseline |
90% | 10% | a tenth of baseline |
99% | 1% | a hundredth of baseline |
This is the same structural reason caching changes a VPS's practical scaling ceiling by orders of magnitude rather than by a modest percentage — a box that can only comfortably handle a modest request rate at 0% hit ratio can handle far more effective traffic once most of it never arrives at all. That relationship is worked through in more depth in how far a €5.50 VPS actually scales.
What does a HIT actually save on the origin's electricity bill, so to speak?
It's worth being concrete about what a HIT skips, because "the origin doesn't have to work" undersells it. On a dynamic page, a MISS typically means: the request reaches the origin, the application framework routes it, any server-side data fetching runs — often a database query or several — the response gets rendered, compressed, and sent back over the network to the edge, which then relays it to the visitor and stores a copy. A HIT skips every single one of those steps. It isn't a faster version of that chain; the chain doesn't run at all.
That's why hit ratio matters more to a small self-hosted box than to a large managed platform with headroom to spare. A single VPS running a database, a reverse proxy, and the application itself has a much smaller margin before something in that chain becomes the bottleneck under real concurrent load — see how far a €5.50 VPS actually scales for the mechanism. Every request a cache HIT intercepts is a request that never gets the chance to compete for that box's CPU, memory, or database connections at all.
Why does the free tier's two-hour TTL floor matter?
Cloudflare's free plan can't set an edge cache TTL below two hours through cache rules, per Cloudflare's own documentation. That floor shapes what you can safely put behind edge caching without a paid plan's finer control. Content that needs to update within minutes of a change — a live dashboard, a frequently-edited admin page — either can't sit behind a two-hour edge cache at all, or needs a cache-busting strategy (a versioned URL, a purge call on publish) rather than relying on TTL expiry alone. For the AI agents and marketing automation angle, see XenGrowth on governed AI marketing workflows.
Static assets — images, CSS, JS bundles with content-hashed filenames — are the easy case: long TTLs are safe because a content change produces a new URL, not a stale cache
Rarely-changing pages — a blog post, a marketing page — fit comfortably within the two-hour floor and beyond
Frequently-changing pages need either a purge-on-publish workflow or need to bypass edge caching entirely for that route
The free tier's 512 MB maximum cacheable object size also matters for anyone serving large downloads or video directly, which sits outside what the CDN tier is meant for anyway
The two-hour floor isn't a limitation to work around quietly. It's a forcing function — it makes you decide, explicitly, what's actually safe to serve stale for two hours, instead of leaving that decision to whatever TTL felt convenient at the time.
What actually determines whether a response is cacheable in the first place?
Being fast to generate doesn't make a response cacheable, and being cacheable doesn't happen by default just because Cloudflare sits in front of the origin. A handful of concrete things determine it, and they're the same things worth checking first when a page you expected to be cached keeps showing MISS.
The HTTP method matters — GET requests are the default cacheable case; POST, PUT, and DELETE generally aren't, by design, because caching a mutation is usually wrong
Response headers matter directly — Cache-Control and its directives (no-store, private, max-age) tell Cloudflare what it's allowed to do, and a framework's default headers on dynamic routes often say don't cache this
Cookies and personalized content complicate caching — a response that varies per logged-in user generally shouldn't be cached the same way for everyone, and needs deliberate handling (cache by cookie, or bypass caching for authenticated routes)
Content type and size play a role — Cloudflare's free tier caps cacheable object size at 512 MB, and some content types are treated differently by default cache rules
Query strings can matter depending on configuration — by default many setups cache by full URL including query string, which means /page?ref=email and /page?ref=twitter can be tracked as separate cache entries unless configured otherwise
This is exactly the kind of thing that trips up image-heavy pages specifically, since responsive images and per-size transformations multiply the number of distinct cacheable variants of what's conceptually "one image." Serving images without Vercel's image optimization walks through that concretely for a self-hosted setup.
Does the free plan's WAF and DDoS protection interact with caching at all?
Worth separating clearly, because it's easy to lump "Cloudflare" together as one feature: the free plan's managed WAF ruleset and unmetered DDoS protection run independently of caching, on every request, whether it's a HIT or a MISS. A cached response still passes through those layers on the way out — caching doesn't bypass security inspection, it just means the origin doesn't have to be the thing absorbing the traffic while that inspection happens. For a small self-hosted box, that's not a minor detail: a volumetric attack or a bad crawler hitting a cacheable route mostly gets absorbed at the edge, while the same traffic hitting an uncacheable route reaches the origin in full.
The free plan does cap how much of this you can hand-tune — five firewall or custom rules, and 1 MB of payload inspected for the WAF, per Cloudflare's own published limits. That's enough for a handful of deliberate blocks and a solid default ruleset, not enough for elaborate custom logic. For most single-server setups, the default managed ruleset plus caching handles the overwhelming majority of junk traffic before it ever becomes the origin's problem, which is most of what a small setup actually needs from it. If AI search, GEO and discovery is the part you are stuck on, XenGrowth on building one SEO and GEO content system is the better reference.
So how do you actually check your own hit ratio?
It's worth checking before you assume caching is doing anything at all, because a Cloudflare-orange-clouded domain isn't automatically a well-cached one. Plenty of setups have every request landing on DYNAMIC or MISS indefinitely, either because the origin's own headers say not to cache, or because the routes that would benefit most from caching are exactly the ones marked as dynamic by the framework's defaults. Assuming it works because the DNS is proxied through Cloudflare is a common enough mistake that it's worth ruling out first, before looking anywhere more complicated.
Two ways, both free, both already available if you're on Cloudflare at all — no separate tool needed, and no reason to quote anyone else's number instead of your own.
Open your browser's network tab, load a page, and inspect the response headers for cf-cache-status — Cloudflare's own documentation defines the values: HIT (served from edge), MISS (fetched from origin, not previously cached or expired), EXPIRED (was cached, TTL ran out), DYNAMIC (marked uncacheable), and a few others
Reload the same URL a second time within the TTL window and watch whether cf-cache-status flips from MISS to HIT — that single check tells you whether the route is caching at all
Check Cloudflare's own analytics dashboard for the zone-wide cache hit ratio over time, which aggregates real traffic rather than a single manual request
If a route you expect to be cached keeps showing MISS or DYNAMIC, check its response headers for Cache-Control directives before assuming Cloudflare is misconfigured — the origin is often the one telling it not to cache
That's the whole method: look at cf-cache-status per request for the mechanism, and the analytics dashboard for the aggregate trend. Both are already sitting in front of you if you're using Cloudflare at all, which makes quoting someone else's hit ratio instead of checking your own a strange choice — the real number is a network tab away.
The bigger picture — how the browser cache, the CDN edge cache, and Next.js's own server cache interact, and why a deploy can look correct at the origin while a visitor still sees the old page — is covered fully in browser cache vs CDN cache vs Next.js cache. Reading that alongside checking your own cf-cache-status header is the difference between guessing why a page feels slow and actually knowing which layer is responsible. If you want a second pair of eyes on a caching setup that isn't behaving the way you expect, that's the kind of work I take on through services.
Further reading from XenGrowth
The XenGrowth resource library — what you'll learn: how the commercial side of this work is run, across search, automation and revenue operations.
XenGrowth on governed AI marketing workflows — what you'll learn: how the teams running AI marketing agents keep them governed and measurable.
XenGrowth on building one SEO and GEO content system — what you'll learn: how search and AI-answer visibility get run as a single content system.
Where this work meets go-to-market
The operational playbooks that sit alongside what cloudflare's cache actually does for speed and bandwidth live with XenGrowth's work on go-to-market systems.
Four questions on reading cache behaviour rather than assuming it. The headers tell you the truth, and the truth is usually less flattering than the dashboard.












