What Cloudflare's Cache Actually Does for Speed and Bandwidth
Cloud

What Cloudflare's Cache Actually Does for Speed and Bandwidth

Cache HIT and MISS aren't a minor speed difference — they're two different request paths entirely, one of which never reaches your server. Here's the mechanism, the free tier's real limits, and exactly how to check your own hit ratio instead of trusting a number nobody measured.

Published September 10, 202611 min readUpdated Sep 6, 2026

Written by · Full-Stack Agentic AI Software Engineer — AI Agents, Automation & Revenue Systems for GTM/RevOps teams

In brief

What does Cloudflare's cache actually do to page speed and origin bandwidth, and how do you check it's working on your own site instead of assuming it is?

A cache HIT is answered entirely at Cloudflare's edge and never touches the origin server; a MISS makes the full trip to origin, runs the app, and only then gets cached for the next request. That structural difference is why hit ratio drives origin egress by orders of magnitude rather than a percentage, and why the free tier's two-hour minimum edge TTL and what's actually cacheable both matter more than most setups account for. Check the real number with the cf-cache-status header and the analytics dashboard — not a number someone else quoted.

  • A cache HIT is served entirely from Cloudflare's edge network and never reaches the origin; a MISS makes the full round trip and only then populates the cache
  • Hit ratio determines origin egress directly — a site at 90% hit ratio sends roughly a tenth the traffic to origin of one at 0%, for the same visitor volume
  • Cloudflare's free tier can't set an edge cache TTL below two hours through cache rules, which shapes what you can safely cache there
  • Cacheability depends on response headers, HTTP method, and content type — not everything that could be fast is actually eligible to be cached
  • The cf-cache-status response header and Cloudflare's own analytics dashboard are how you check your real hit ratio, not a number quoted from someone else's site

Evidence notes

Cloudflare free plan cache limits

Free tier: 5 firewall/custom rules, 1 MB WAF payload inspection, 512 MB max cacheable object size, and a 2-hour minimum edge cache TTL enforceable via cache rules — checked September 2026

cf-cache-status header values

Cloudflare's own documentation defines HIT, MISS, EXPIRED, DYNAMIC, and other cf-cache-status values returned on every proxied response, used to verify whether a given request was actually served from cache

Cloudflare free plan feature set

Free plan includes unmetered DDoS protection, global CDN, Universal SSL and a free managed WAF ruleset — verified on Cloudflare's own plans page, checked 7 September 2026. The developer-docs page this previously cited has since been retired.

Continue with purpose

"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.

  1. 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

  2. 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

  3. 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)

  4. 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

  5. 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.

  1. 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

  2. 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

  3. 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

  4. 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

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.

What is the cache actually doing?

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.

1 / 4
A response comes back with a MISS on every request for the same static file. What's the most likely cause?

Apply this article

How to turn insights into execution

A practical sequence for teams turning concepts into production outcomes.

CloudflareCDNCachingPerformanceBandwidthSelf-Hostingcloud

Audit your current state

Map the bottlenecks and constraints connected to the article’s core problem.

Choose one bounded change

Test the most useful recommendation on one workflow before widening the scope.

Measure what changed

Keep the parts that improve the work, document what failed, and make the next decision from evidence.

Next step

Need help applying this in your stack?

I can translate these patterns into a concrete implementation plan for your team.

Discuss implementationBack to blog

Replies usually within 24 hours.

Next Steps

Continue reading

What Cloudflare's Free Tier Actually Does for a Self-Hosted App

Cloudflare's free plan gets recommended for every self-hosted setup, usually without anyone saying what it doesn't cover. Here's what $0 genuinely buys a one-person VPS, checked against 2026 pricing, and exactly where it stops.

Navigate

Why Next.js Feels Slow on a VPS — and the Six Things That Fix It

The app that felt instant on Vercel goes home to a cheap VPS and forgets how to load fast. The framework didn't change. Six specific things underneath it did, and none of them are next/image.

Navigate

My Complete Self-Hosted Stack for SaaS in 2026

Contabo, Coolify, Docker, Cloudflare, Postgres, R2, Resend, Uptime Kuma, Turborepo and Docker Hub. Here's every piece of the stack I actually run, what each one replaced, and why I picked it over the alternatives.

Navigate

What "Unlimited Bandwidth" Really Means on a VPS

Nobody actually gets an unbounded pipe to the internet for $7 a month. What you get is a port speed, a fair-use clause, and a provider's word that they'll throttle you before they bill you.

Navigate

Cloudflare Tunnel vs Reverse Proxy: Which One Should You Use?

One of these opens no inbound ports and works behind CGNAT. The other is simpler, portable, and doesn't ask you to trust a daemon or a vendor's uptime with every request. Neither one is the obviously correct default — the right answer depends on which failure you'd rather own.

Navigate

Preview Environments Without Vercel: Branch Deploys on Your Own VPS

A preview URL per branch is the one Vercel feature people miss most after leaving. It's buildable on your own server, and it's genuinely harder than Vercel makes it look — mostly because of the database, which nobody's marketing page mentions.

Navigate

How Far a €5.50 VPS Actually Scales: What the Numbers Say

Nobody's benchmark is your app's benchmark. Instead of quoting a number nobody ran, here's the actual mechanism that caps a 4 vCPU / 8 GB box, how caching changes the arithmetic by orders of magnitude, and exactly how to load-test your own workload.

Navigate

The Contabo + Coolify + Cloudflare Stack That Replaced My Vercel Bill

Three pieces, not thirty. Here's exactly what each one does, why that specific combination and not one of the dozen others I considered, and which parts of Vercel each one is actually standing in for.

Navigate

How I Use Cloudflare to Hide My Origin Server

Turning on the orange cloud doesn't hide anything by itself. It hides your origin only if you also make the origin refuse to talk to anyone who isn't Cloudflare — and there are at least four ordinary ways your real IP gets out anyway if you skip that part.

Navigate

How I Self-Host PostgreSQL for My SaaS (and When I Wouldn't)

Running Postgres in a container is easy. Running it in a way that survives a redeploy, a full disk, and an eventual major-version upgrade is the actual job. Here's the setup, tuned against Postgres's own defaults, and the honest list of where managed wins outright.

Navigate