Cache hit ratio: what it is and how to get yours above 95%
It is the one number that tells you whether your CDN is actually doing its job. What it means, the five things that usually wreck it, and how to work out which one is wrecking yours.
You put the site behind a CDN, the dashboard has been up for a week, and the cache hit ratio says 61%. Is that bad? Should you be worried? What do you even do about it?
This comes up a lot, and the honest answer is that 61% is probably bad but not necessarily — it depends entirely on what your site is. So let us start with what the number actually means, then work through diagnosing yours, because the fix is nearly always one of five specific things.
What the number means
Every request your CDN receives ends one of two ways. A hit means the edge already had a fresh copy and served it immediately. A miss means it did not, so it asked your origin, waited, relayed the answer, and kept a copy for next time. Cache hit ratio is hits divided by total requests.
A miss is not just slower for that one visitor. It is a request your origin has to handle, bandwidth you pay for on both legs, and a little less headroom for when traffic spikes. Multiply a low ratio across millions of requests and you are running a global network as an expensive passthrough.
Requests or bytes?
Worth knowing before you compare numbers with anyone: some dashboards report hit ratio by request count, others by bytes served. They can differ wildly. A site serving one enormous uncached video among a million small cached assets has a superb request ratio and a dreadful byte ratio. If your bandwidth bill and your hit ratio seem to disagree, this is usually why — check which one you are looking at.
What is actually a good ratio?
The "above 95%" in the title is a reasonable goal for most sites, but it is not universal, and chasing it on the wrong kind of site is wasted effort.
| Site type | Realistic target | Why |
|---|---|---|
| Static site, docs, marketing | 98%+ | Almost nothing is personal |
| Blog or publisher | 95–98% | Long-lived pages, heavy asset reuse |
| Shop with full-page caching | 85–95% | Cart, checkout and account always bypass |
| Asset-only zone (images, JS, CSS) | 99% | If it is lower, something is misconfigured |
| Logged-in app | Varies wildly | Judge assets and pages separately |
Two things follow from that table. First, if you run a shop, do not panic at 88% — a chunk of your traffic is checkout and account pages that must never be cached, and excluding them correctly is the system working. Second, if you have a separate zone for static assets and it is below 99%, that is a genuine misconfiguration and worth ten minutes of your time.
Diagnosing a low ratio
In rough order of how often each turns out to be the culprit:
1. Your origin is telling the CDN not to cache
This is the most common cause by a distance, and the most satisfying to fix because it is usually one header. A stray Cache-Control: no-store, private, or max-age=0 tells the edge to skip caching entirely. Frameworks add these by default more often than you would expect, particularly for HTML.
Check what your origin actually sends, not what you think it sends:
curl -sI https://origin.example.com/some-page | grep -iE 'cache-control|set-cookie|vary'
2. Query strings are fragmenting the cache
If /product, /product?utm_source=newsletter and /product?fbclid=abc123 are three separate cache entries, one popular page has quietly become several hundred entries, each with an audience of one. Every share on social media creates a brand new cache key that will never be requested again.
Strip tracking parameters from the cache key. They matter to your analytics, which reads them in the browser, and not at all to which bytes you return.
3. Cookies on things that do not need them
A Set-Cookie header on a static asset makes the CDN treat that response as personalised and refuse to store it. Your logo does not need a cookie. Session middleware that runs on every route, including asset routes, is the usual source.
4. TTLs are too short
If content expires after 60 seconds, the edge spends its life re-fetching things that did not change. Fingerprinted assets — app.a1b2c3.css — can safely be cached for a year, because a new version gets a new filename. HTML usually wants something shorter, but "shorter" can still mean hours if you can purge on publish.
5. A Vary header you did not mean to send
The subtle one. Vary: User-Agent makes the edge store a separate copy per user-agent string, and there are effectively unlimited user-agent strings. Your hit ratio collapses and nothing in your config looks wrong. Vary: Accept-Encoding is fine and expected; almost anything else deserves a second look.
If you only do one thing: sort your CDN logs by cache status, filter to misses, and group by URL. The top twenty misses will tell you which of the five above you have, usually within a minute. Guessing takes longer than looking.
Why 100% is the wrong goal
You cannot reach 100%, and a site that did would be suspicious. Cache entries legitimately expire. New content has to be fetched once. Purges empty the cache on purpose. And a genuinely personalised page — a cart, an account dashboard — should miss every time, because caching it would be a bug and potentially a data leak.
The number to watch is not the absolute value so much as its shape over time. A ratio that was 96% and is now 78% means something changed: a deploy altered your headers, a campaign added new query parameters, or someone shipped a cookie on your asset routes. Sudden movement is a signal. A steady 91% on a shop is just Tuesday.
Frequently asked questions
What is a good cache hit ratio?
It depends on the site. A static or marketing site should reach 98% or higher, a blog 95 to 98%, and a shop using full-page caching typically 85 to 95%, because cart, checkout and account pages must always bypass the cache. A zone serving only static assets should be at 99%; anything lower usually indicates a misconfiguration.
How do I improve my cache hit ratio?
Work through five causes in order: cache-control headers on your origin that prevent caching, query strings such as utm_source fragmenting one page into many cache entries, Set-Cookie headers on static assets, TTLs that are too short, and an over-broad Vary header such as Vary: User-Agent. Sorting your CDN logs by cache status and grouping misses by URL identifies which one applies faster than guessing.
Why is my cache hit ratio low even though caching is enabled?
Almost always because something in the response tells the CDN not to store it. The usual culprits are a Cache-Control header of no-store, private or max-age=0 sent by your application framework, a Set-Cookie header on responses that should be shared, or a Vary header that varies on something with unlimited values such as User-Agent. Run curl -I against your origin and inspect the actual headers.
Does a cache miss slow down the visitor?
Yes. A cache hit is typically served in under 20 milliseconds from the nearest edge, while a miss requires a full round trip to your origin plus whatever time your origin needs to generate the response — commonly 200 milliseconds or more, and considerably worse for visitors on another continent. Every miss also consumes origin capacity and bandwidth you pay for.
Should I aim for a 100% cache hit ratio?
No. Cache entries legitimately expire, new content must be fetched at least once, and purges empty the cache deliberately. Genuinely personalised pages such as carts and account dashboards should miss every time — caching them would be a bug and a potential data leak. Watch for sudden drops rather than chasing an absolute number.
So: 61%. Pull your miss list, look at the top twenty URLs, and there is a good chance you are looking at either an unintended no-store or a pile of ?utm_source= variants. Both are a config change, not a project.
See how NordicCDN does this for your site:
Mads has worked in IT — mostly hosting — since he was 16. He took an early stake in a SaaS company and helped grow it through to its acquisition by Visma, has built and run data-center networks, and served as CTO of a Danish data center. He started NordicCDN to make fast, secure infrastructure simple to use.