Cloudflare · 9 min read · Oct 12, 2026
After the Static Assets: Where Cloudflare Performance Is Actually Won
Default caching handles images, CSS and JavaScript. The larger gains sit in HTML, API responses, cache keys and origin trips that nobody tuned.
Putting a site behind Cloudflare makes static files fast on day one, with no effort. That result convinces many teams the performance work is finished. It is not: the requests that decide how fast your pages feel are usually the ones the default configuration deliberately leaves alone, and tuning them is a matter of knowing your own traffic, not of switching on more features.
Start with one response header
Before changing a rule, look at what is happening now. Every proxied response carries a cf-cache-status header. Its common values tell you most of the story:
| Value | Meaning | What to do about it |
|---|---|---|
HIT | Served from the edge cache | Nothing. This is the goal. |
MISS | Eligible for cache, but not in this location yet | Normal on first request. A high share suggests fragmented cache keys or short TTLs. |
EXPIRED | Was cached, TTL ran out, fetched again | Consider a longer TTL or revalidation. |
REVALIDATED | Stale copy confirmed fresh with the origin | Cheap. Good sign that validators work. |
BYPASS | Something told the edge not to cache | Find out what: an origin header, a cookie, a rule. |
DYNAMIC | Not considered cacheable by default | This is your opportunity list. |
Pull a day of traffic grouped by path pattern and by this header. Sort by request count. The top of the DYNAMIC and MISS groups is where your tuning time should go. In most applications the list is short: the HTML of a few high-traffic pages, and a handful of API endpoints that every page load calls.
What the default covers, and the middle tier it skips
By default the edge caches by file extension: images, stylesheets, scripts, fonts and similar static types. It does not cache HTML or JSON unless you tell it to, and it honors the caching headers your origin sends. That is a sensible, safe default, because the platform cannot know whether your HTML is the same for everyone.
This leaves three tiers of content:
- Static assets. Already handled. The only improvement left is long TTLs with fingerprinted filenames, so a deploy changes the URL and never needs a purge.
- Truly per-user responses. Account pages, carts, anything behind authorization. These must stay dynamic.
- The middle tier. Content that changes, but not per request and not per user: a product listing, a pricing page, a public catalog API, search suggestions, a store locator, a rendered marketing page.
The middle tier is where the unclaimed performance is. Each time such a request makes the full trip to your origin, the visitor waits through an extra round trip and your servers burn compute on an answer they already produced seconds ago.
A worked example
Picture a distributor whose product listing page calls /api/catalog?category=fasteners on every load. The data changes when the inventory sync runs, every few minutes. The endpoint takes 400 ms at the origin and is called thousands of times an hour.
A cache rule matching that path with an edge TTL of 60 seconds changes the arithmetic completely. Within each location, one request per minute per distinct URL reaches the origin. Everyone else gets an answer from a nearby data center in a few milliseconds. The data is at most a minute old, in a system where it was already minutes old by design. Nothing in the application changed.
This pattern, short TTLs on hot and shared responses, is sometimes called microcaching. It is the highest-leverage rule on most sites, and it is rarely written, because nobody owns the question "which dynamic responses are actually shared?"
Cache keys: why a cacheable response still misses
The cache key is what the edge uses to decide whether two requests are the same. By default it includes the full URL with the query string. That detail quietly ruins hit ratios.
- Tracking parameters.
?utm_source=..., click IDs and similar values make every ad click a unique URL, so every ad click is a miss. Excluding known marketing parameters from the cache key, or ignoring the query string entirely for pages that do not use it, can turn a campaign landing page from mostly misses into mostly hits. - Parameter order and casing.
?a=1&b=2and?b=2&a=1are different keys unless you normalize them. - Cache busters you forgot about. A legacy
?v=timestampgenerated per request defeats caching by design. - Variation you actually need. If the response differs by language, device class or country, that dimension has to be in the key, or people get the wrong variant. Be precise: vary on the two or three values that matter, not on a raw header with thousands of possible values.
Note that edge caches generally do not treat the Vary response header the way a browser does. If your origin relies on Vary to separate variants, verify how the edge handles it before assuming it works.
The rule that leaks data
Aggressive caching has one failure that is worse than being slow: serving one user's response to another user. It happens when a "cache everything" rule, often copied from a guide written for static sites, is applied to a path that returns personalized content.
Guardrails that should be in place before any HTML or API caching goes live:
- Scope rules by path, narrowly. Cache
/api/catalog/*, not/api/*. - Bypass on session. If a session cookie or an
Authorizationheader is present, skip the cache, unless you have proven the response does not depend on it. - Never cache a response that sets a cookie. A cached
Set-Cookiehands one visitor's session to the next. - Make the origin explicit. Private responses should say
Cache-Control: privateorno-store. Public ones should saypublicwith amax-ageors-maxage. Edge rules then act as a second layer, not the only one. - Test with two accounts. Log in as user A, load the page, then load it as user B from the same region. Check the header and the content.
- Review cache rules like code. A change to what is cached is a change to what users see. It deserves a second pair of eyes and a rollback plan.
Freshness without fear
Teams keep TTLs short because they are afraid of stale content. There are better tools than a short TTL.
Purge on change. When content changes, tell the edge. Purging by URL is simple. Purging by tag or prefix lets one event ("product 4417 updated") invalidate every page that includes it. With reliable purging in place, TTLs can be long, and the hit ratio rises accordingly.
Serve stale while revalidating. With the right directives, the edge can return a slightly stale copy immediately and refresh it in the background, so no visitor waits for the origin. Related directives let the edge keep serving a stale copy if the origin is returning errors, which turns a short origin outage into a non-event for cached pages.
Split the shell from the fragment. A page that is 95 percent identical for everyone and 5 percent personal does not have to be all dynamic. Cache the shell, and load the personal part (the cart count, the greeting) with a small uncached request after render.
Fewer and shorter trips to origin
Caching reduces how often you go to origin. The next layer reduces how many locations go there and how long the trip takes.
Tiered caching. Without it, each edge location that misses fetches from your origin independently. With a tiered topology, lower-tier locations ask an upper-tier location first, so a single origin fetch can fill many edges. For content with a long tail of rarely requested URLs, this raises the effective hit ratio noticeably.
Persistent cache storage. Edge caches evict content that is not requested often, regardless of TTL. A persistent storage layer for cache keeps long-tail assets available for their full TTL. It is worth pricing when your origin egress bill is a concern or your library is large.
Smart routing. Argo Smart Routing sends origin-bound requests over paths chosen from live network measurements instead of the default internet route. It helps most when the uncacheable requests matter and the visitors are far from the origin: an API serving Asia from a single US region, for example. It is a paid add-on billed on usage, so measure before and after on your own traffic.
Protocol basics. Confirm HTTP/2 and HTTP/3 are enabled toward visitors, that connections to the origin are reused, and that TLS between edge and origin is not being renegotiated on every request. These are settings, not projects, and they are often left at whatever they were years ago.
The bytes themselves
Once the path is short, what remains is payload size.
Images. Usually the largest share of page weight. Polish re-compresses images and can serve modern formats to browsers that accept them, with no change to your markup. Image transformations go further: resize to the dimensions the layout needs, at request time, from one high-resolution original. Sending a 2,400 pixel image to a 400 pixel slot is the most common single waste on the web.
Compression. Text responses should leave the edge compressed with a modern algorithm. Check that your origin is not sending already compressed responses that prevent the edge from doing better, and that your JSON API responses are included.
Early hints and preloading. The edge can tell the browser about critical assets before the HTML arrives, so the stylesheet and hero image start downloading during origin think time. This improves Largest Contentful Paint on pages whose HTML is slow to generate.
Script handling features. Options that defer or rewrite JavaScript automatically can help on simple sites and break things on complex ones. Test them on a staging hostname, never by toggling in production.
Rules or code: the build-versus-buy line
You can write caching logic in a Worker: custom keys, per-segment variants, stitching fragments, signed URLs. Sometimes that is the right call, when the logic cannot be expressed in the rule engine (caching by a claim inside a token, for example, or composing a page from several origins).
For the common cases it is the wrong one. A Worker in the request path is code you now own: it needs tests, monitoring, deployment discipline and someone who understands it in two years. If a cache rule and correct origin headers achieve the result, use those.
A reasonable test: write down the behavior you want in one sentence. If the sentence fits the rule engine's vocabulary (match these requests, use this key, keep for this long, bypass on this condition), buy. If it needs the word "unless" three times, consider building.
Measure first, change one thing
None of this replaces fixing a slow endpoint. If the origin takes three seconds, the edge can hide it for cached requests and cannot hide it for the rest. Fix the query, then tune the edge.
When you do tune:
- Use field data, not only lab tests. Core Web Vitals (Largest Contentful Paint, Interaction to Next Paint, Cumulative Layout Shift) are measured on real visitors. A lab test from one fast location tells you little about a phone on a mobile network.
- Segment. Look at time to first byte by country and by cache status. Averages hide the visitors who are having a bad time.
- Isolate each change. Ship a single adjustment, then let it run through a full weekly traffic cycle before you judge it or stack the next one on top.
- Watch the origin too. A good caching change shows up as lower origin request volume and CPU. If the hit ratio rises and origin load does not fall, something is off.
- Keep a rollback. Every rule should be removable in one step, and the purge procedure should be written down.
A sensible order of work: inspect cache status, fix cache keys, add microcaching for the middle tier with leak guardrails, set up purge so TTLs can grow, enable tiered caching, then deal with images, and only then evaluate paid routing and custom code.
How many of your busiest requests are still going to origin when they do not need to?
If you cannot answer from memory, the list of DYNAMIC responses on your top paths will tell you in an afternoon. Trivo's Cloudflare implementation work includes this kind of tuning (cache rules, origin routing, image handling), and it always starts from your real traffic, with each adjustment measured before the next is made. Bring your traffic patterns and we will map what is safe to cache and what it is worth.
Share this article
Keep reading
Strategy · 9 min read
The License Fee Is the Small Number: A Working Guide to Build or Buy
Buying software is usually right, until the product sits on top of how you make money. How to sort capabilities, price the hidden costs and decide.
Oct 12, 2026 Read
Cloudflare · 9 min read
The Cloudflare Signals You Need Wired Up Before Something Breaks
Cloudflare records plenty by default. Whether a person hears about a problem in time depends on choices made in a quiet week, not mid-outage.
Oct 12, 2026 Read
Cloudflare · 9 min read
Managed Rules Know the Internet. Custom Rules Have to Know Your Application.
Cloudflare's managed WAF and DDoS rules stop generic attacks. Logins, APIs, bots and false positives still need rules written from your own traffic.
Oct 12, 2026 Read