CDN Cache Key Design: Query Strings, Cookies and Hit Ratio

A CDN cache key is the tuple the edge hashes to decide hit or miss, and on most platforms the default is scheme, host, path and the entire query string. That default is why an object capable of a 99% cache hit ratio often measures under 40%: one unfiltered click identifier splits a single cacheable response into hundreds of key variants, each needing its own origin fill. Cookies make it worse, because a single Vary on Cookie multiplies the key space by the number of distinct session values. Cache key composition, not TTL tuning, is usually the fastest available origin offload win.

Diagram of CDN cache key composition showing query string and cookie normalization and their effect on cache hit ratio

What a CDN cache key actually contains

Every edge platform builds the key from two layers. The primary key is derived from the request target: scheme, host, path, method, and whatever part of the query string the configuration admits. The secondary key comes from the response, through Vary, as described in RFC 9111: the origin declares which request headers select among stored variants, and the edge stores one object per header combination.

Most operators only configure the first layer and then get surprised by the second. Your query string allow-list can be perfect while the origin quietly emits Vary on User-Agent, which in practice means a distinct stored object per browser build string. That is tens of thousands of variants for one URL.

The dimensions a CDN cache key can carry

  • Path and host: cheap, deterministic, almost never the problem.
  • Query string: the largest source of accidental cardinality, because marketing and analytics tooling appends parameters the origin ignores.
  • Cookies: either an explicit key dimension or an implicit one via Vary on Cookie. Raw session identifiers make the key unique per user, which is a cache with a 0% hit ratio and extra latency.
  • Accept-Encoding: legitimate, but must be bucketed to brotli, gzip and identity rather than keyed on the raw header string.
  • Device class, country, language: legitimate when the origin genuinely varies, expensive when it does not.

Why query strings and cookies destroy cache hit ratio

Cache hit ratio has a hard ceiling set by cardinality, and that ceiling is arithmetic, not a tuning opinion. For an object requested R times per second at one cache node with TTL T, each distinct key variant costs exactly one miss per TTL window:

max hit ratio = 1 minus (V times Nodes) divided by (R times T), where V is the number of distinct key variants per object

Assumptions: variants are requested at roughly equal frequency, nothing is evicted before TTL expiry, and Nodes is the number of independent cache tiers a request can land on without a shield in front of them. Both simplifications are generous, so the table below is an upper bound, not a forecast.

Key variants per objectMisses per TTL windowMax cache hit ratioTypical cause
1199.9%Fully normalized key
8899.3%Allow-listed params, unsorted order
505095.8%Campaign parameters on landing pages
50, spread over 12 uncoordinated cache nodes60050.0%No shield or tiered cache
80080033.3%Raw query string plus Vary on User-Agent

Baseline for all rows: 2 requests per second per object and a 600 second TTL, which gives 1,200 requests per TTL window; the single lever that moves the ceiling is variant count, not TTL length.

Cache key cardinality sets a hard ceiling on hit ratio: an object requested 1,200 times per TTL window can reach 99.9% cache hit ratio with one key variant, but only about 33% if tracking parameters split it into 800 variants. In 2026 traffic the dominant cause of that split remains unfiltered marketing parameters such as the Google click identifier gclid, Facebook's fbclid, and the utm family.

Cache normalization rules that recover origin offload

Cache normalization is the deterministic transform applied to the request before the key is hashed. Order matters, because sorting before filtering wastes work and filtering after cookie folding leaks identifiers into the key.

A CDN cache key normalization pipeline worth copying

  1. Lowercase the host, strip the default port, discard the fragment.
  2. Drop every query parameter that is not on a per-route allow-list. Allow-lists beat deny-lists because new tracking parameters ship every quarter and a deny-list is always one campaign behind.
  3. Sort the surviving parameters lexicographically by name, then by value, so that two orderings of the same parameters produce one key.
  4. Drop parameters whose value is empty unless the route declares emptiness meaningful.
  5. Fold cookies into a derived dimension with at most four values, computed at the edge from the cookie, for example anonymous, member, plan-pro, plan-enterprise. Never put a raw session value in the key.
  6. Bucket Accept-Encoding to brotli, gzip or identity before it reaches the key or the Vary logic.
  7. Bypass rather than key: authenticated requests to private routes should skip cache lookup and storage entirely, with no-store enforced at the edge.

On an nginx origin the equivalent is a cache key assembled from scheme, upstream host, the normalized URI, and a single args variable produced by a map that applies steps 2 through 4. On Varnish it lives in the request hash function. On edge-compute platforms it is a request rewrite executed before the cache lookup. The mechanism differs; the ruleset does not.

Trade-offs and failure modes

Stripping a parameter that the origin actually reads produces a correctness bug that looks like a caching bug. Image resize parameters, API version selectors, pagination offsets, and locale switches must be explicitly allow-listed per route, which means the allow-list becomes a piece of application contract that belongs in code review.

Cookie folding is the highest-risk rule in the list. If the derived dimension is computed wrong, the edge serves one tenant's page to another. Treat the fold function as security-critical code and add a synthetic test that requests the same path with three different cookie classes and asserts three different response bodies.

Aggressive normalization also complicates invalidation. Once the key admits three allow-listed parameters, purging one logical URL means purging a key prefix, and not every platform supports prefix or surrogate-key purge with the same latency as single-URL purge. Verify purge semantics before you widen the key. Broad normalization plus slow prefix purge equals stale content you cannot remove quickly.

Finally, cardinality interacts with storage. Variants that are individually small still consume index entries and shorten effective retention for everything else on the node. Platforms with NVMe SSD edge storage, including BlazingCDN's edge cache configuration features, absorb a wider key space with fill latency rather than eviction, but no storage tier turns a per-user key into a useful cache.

Verify this on your own stack

  • Segment your cache status header by presence of a query string. A gap wider than 10 percentage points means query string caching is your top offload defect.
  • From one day of edge logs, compute distinct cache keys divided by distinct URLs. Above 3:1, normalization pays. Above 20:1, it outranks every other caching change on your backlog.
  • Divide origin requests per second by edge requests per second. That ratio is your real offload, and it is what shows up on the origin egress invoice.
  • Inspect origin responses for any Vary value other than Accept-Encoding. Vary on Cookie or on User-Agent multiplies the cache key silently and never appears in your CDN configuration.

FAQ: CDN cache key design and cache hit ratio

Does a query string always cause a CDN cache miss?

No. A query string only causes a miss if the CDN cache key includes that parameter and the exact value has not been fetched before. When the edge is configured to ignore or allow-list parameters, two URLs differing only in tracking parameters collapse to one key and one cached object, which is the normal fix for query string caching problems.

Should Vary on Cookie ever be used with a CDN?

Rarely, and never with raw session cookies. Vary on Cookie makes the stored variant depend on the full cookie header, so each user gets a private variant and shared caching stops. The safer pattern is folding the cookie into a low-cardinality class at the edge and keying on that derived value instead.

What is a good cache hit ratio in 2026?

Typical healthy targets are 95 to 99% for versioned static assets, 90% or higher for segmented video, and 70 to 90% for mixed HTML and API traffic where personalization is real. Ranges are indicative rather than universal; the useful comparison is your own ratio before and after cache normalization.

How do signed URLs interact with cache key design?

Signature parameters must be validated at the edge and then excluded from the CDN cache key. If expiry timestamps and signatures stay in the key, every issued link creates a unique variant and hit ratio collapses toward zero. Validate first, strip second, hash third, and keep the underlying object keyed on path alone.

Run the cardinality audit this week

Pull 24 hours of edge logs, group by path, and count distinct cache keys per path. Sort descending. The top twenty rows will explain most of your missing hit ratio, and in most stacks fewer than ten parameters are responsible. Ship an allow-list for those paths behind a canary, watch the origin requests per second curve for an hour, and record the before and after offload ratio. If the numbers move, post them to your team with the parameter list attached. If they do not, your Vary headers are the next place to look.

Heavy traffic.
Light bill.

The CDN for video and large traffic