Every cache decision reduces to one question: do these two requests get the same stored object? The cache key answers it, and a key with one careless component can turn one object into ten thousand stored variants — which is why key design is billing design. This is the checklist.
What a cache key is actually made of
Every CDN builds a key from the request to look up stored responses; the default is usually host + path + query string, with scheme and sometimes protocol mixed in, and platform-specific extensions letting you add headers, cookies or computed values. Two requests with identical keys share a cache entry; any difference — a reordered query parameter, a device-classification header you added for one experiment — creates a separate entry with its own miss, its own origin fetch, its own storage. The design goal is exact sufficiency: every component that genuinely changes the response is in the key, and nothing else is. Err in one direction and you serve wrong content; err in the other and you shred your hit ratio — the direction people actually err.
The include list: what earns its place
A component earns a place in the key only if the origin returns different bytes because of it. The usual legitimate members beyond host and path: the query parameters that select content (IDs, pagination, search terms, the ?ver= of versioned assets); a language or country dimension where you serve localized variants (prefer a normalized value — a computed country code — over raw Accept-Language, which has thousands of distinct values in the wild); a device class where you genuinely serve different HTML (again normalized to two or three buckets, never the raw User-Agent); and content negotiation that changes encoding — though modern platforms handle compression variants internally, so check before adding Accept-Encoding yourself. For each candidate, ask for the proof: show two requests differing only in this component that receive different origin responses. No proof, no key membership.
The normalize list: what must not fragment you
The other half of design is actively excluding what varies without meaning. Tracking parameters (utm_*, click IDs, session-less analytics tokens) are the classic offender — one campaign email can mint thousands of variants of your homepage; strip or ignore them in the key. Parameter order and case: ?a=1&b=2 and ?b=2&a=1 are the same request to your origin and different keys to a naive cache — enable sorting/normalization where the platform offers it. Cookies stay out of the key entirely unless a specific cookie legitimately selects content (and then key on that one cookie's value, never the whole header). And trailing-slash, default-port and duplicate-slash variants deserve normalization at the edge before they mint entries. Every item here is invisible in testing — your test requests are consistent — and expensive in production, where the wild's requests are not.
Query strings: the main battlefield
Most platforms offer three query-string modes — include all, ignore all, include/exclude listed parameters — and the listed mode is almost always correct for HTML and APIs. Include-all is safe for versioned static assets (where the query is the cache-buster and belongs in the key, per the versioning guide) and dangerous everywhere marketing links exist. Ignore-all maximizes hit ratio and silently breaks anything that legitimately varies by parameter. So: enumerate the parameters each route actually uses, whitelist those into the key, and let everything else fall away — a per-route exercise that takes an hour with your router's documentation open and pays every month thereafter. Where your platform's rules engine allows per-path key policies (see the rules engines comparison for who allows what), give static assets, HTML and APIs their three different policies rather than one compromise.
The fragmentation audit
Fragmentation announces itself as a hit ratio lower than your content's repetition justifies — the diagnosis discipline of the hit-ratio guide. To find it: pull a day of logs, group requests by the URL your origin would consider identical (path + whitelisted params, normalized), and count distinct cache keys per group. Groups with high key-counts are your leaks, and the offender is visible in the keys themselves — a rogue parameter, an un-normalized header, a cookie in the key. Fix, purge the affected paths, and re-measure a week later. Run the audit quarterly and after every marketing-tooling change; new tracking parameters are born constantly, and each one is a small tax on your bill until the whitelist catches it.
