In CloudFront, what decides the cache key for a request, and what happens to a query string, cookie or header that is named in neither the cache policy nor the origin request policy attached to the cache behavior?
answer
- two policies, two different jobs
- one composes the key, one only forwards
- named nowhere means never sent
- cardinality multiplies stored objects
basics
~20 sCloudFront's cache key is the distribution, the matched cache behavior and exactly the query strings, headers and cookies named in the attached cache policy. Values named in neither policy are stripped, so the origin never sees them at all.
solid answer
~50 sA CloudFront cache behavior carries a **cache policy** and, optionally, an **origin request policy**, and they do different jobs. The cache policy decides the cache key: the URL path plus whichever query strings, headers and cookies it names, and those values are also forwarded to the origin. The origin request policy only decides what is *forwarded* — values it names reach the origin but do not create separate cached copies. Anything named in neither is dropped before CloudFront builds the origin request, which is why a freshly fronted app suddenly stops seeing `?q=`, its session cookie or its `Authorization` header. The design forces you to answer two separate questions: what makes two requests genuinely different responses (cache key), and what the origin merely needs to do its job (forwarded). Putting per-user values such as a session cookie in the cache policy is the classic mistake — it keys the cache per user and collapses the hit rate.
code
json · 16 lines{
"Name": "app-lang-only",
"MinTTL": 1,
"DefaultTTL": 86400,
"MaxTTL": 31536000,
"ParametersInCacheKeyAndForwardedToOrigin": {
"EnableAcceptEncodingGzip": true,
"EnableAcceptEncodingBrotli": true,
"HeadersConfig": { "HeaderBehavior": "none" },
"CookiesConfig": { "CookieBehavior": "none" },
"QueryStringsConfig": {
"QueryStringBehavior": "whitelist",
"QueryStrings": { "Quantity": 1, "Items": ["lang"] }
}
}
}go deeper
Know that CloudFront only forwards what a policy names, and that a missing query string or cookie at the origin usually means no policy named it.
Be ready to explain the split precisely: cache policy equals cache key plus forwarded, origin request policy equals forwarded only, unnamed equals dropped — and to place a given header on the right side.
Show you reason about key cardinality under load: name the values that genuinely change the body, keep high-cardinality ones out, and diagnose a poor hit rate from X-Cache plus policy contents rather than guessing.
Own the standard: a small set of blessed cache behaviors and policies teams reuse, so nobody hand-rolls a policy keyed on a session cookie, plus a review rule that any new cache-key value states its cardinality and its cost.
## Two policies, two questions Every CloudFront cache behavior attaches a **cache policy**, and may also attach an **origin request policy**. Beginners treat them as one setting with two names; they are not. - The **cache policy** answers: *what makes two viewer requests different enough to deserve different cached responses?* Everything it names goes into the **cache key**. As a side effect, those values are also sent to the origin. - The **origin request policy** answers: *what else does my origin need in order to build a response?* Everything it names is **forwarded** to the origin but is **not** part of the cache key, so it produces no extra cached copies. - Anything named in **neither** policy is **removed** from the request CloudFront sends upstream. That third bullet is the one that bites. CloudFront is not a transparent proxy: it does not forward the viewer's request verbatim. ## What the cache key contains The key always includes the distribution, the cache behavior that matched the path pattern, and the URL path. On top of that, a cache policy declares three lists — query strings, headers and cookies — each with a behavior such as `none`, a named whitelist, or (for query strings and cookies) all / all-except. A policy that names nothing produces a key that is effectively just the path, which is exactly what the managed `CachingOptimized` policy does: no headers, no cookies, no query strings, and Accept-Encoding normalization enabled for compression. That policy is ideal for hashed static assets and disastrous for `/search?q=shoes`, because every distinct `q` collapses onto one cached object and every user gets whoever's results landed there first — and the origin does not even receive the parameter. ## The arithmetic of cache-key cardinality Each value you add to the key multiplies the number of stored objects for a URL. Two languages times three device types is six objects; add a session cookie and the multiplier becomes the number of users, which is the same as no caching at all plus the cost of a CDN. The rule of thumb: a value belongs in the cache key **only if the response body genuinely differs when it changes, and the number of distinct values is small and bounded**. High-cardinality offenders that keep appearing in real policies: `Authorization`, session cookies, `User-Agent` (thousands of distinct strings), analytics query parameters such as campaign tags, and `Referer`. ## Where each thing belongs ```json { "QueryStringsConfig": { "QueryStringBehavior": "whitelist", "QueryStrings": { "Quantity": 1, "Items": ["lang"] } }, "HeadersConfig": { "HeaderBehavior": "none" }, "CookiesConfig": { "CookieBehavior": "none" } } ``` A `lang` parameter with five values belongs in the cache policy: five cached variants, all shared across users. An `Authorization` header belongs in the origin request policy: the origin needs it, but authenticating per user must not create per-user cached objects — and if the response is genuinely user-specific, it should not be cached at all (the managed `CachingDisabled` policy exists for that behavior). AWS ships managed policies for the common shapes — `Managed-CachingOptimized`, `Managed-CachingDisabled` on the cache side, `Managed-AllViewer` and friends on the origin-request side — so the usual production layout is a hashed-asset behavior on `CachingOptimized` and a dynamic `/api/*` behavior on `CachingDisabled` plus an origin request policy that forwards what the backend needs. ## How this shows up as a bug The symptom is almost never "the cache key is wrong". It is: - **The origin behaves as if parameters vanished.** Pagination always returns page 1; search ignores the term. Nothing was forwarded. - **Everyone sees one user's page.** A per-user response was cached under a key that does not include the user, because the cookie was forwarded via the origin request policy — or the origin sent a cacheable response it should not have. - **The hit rate is near zero and the origin is hot.** A high-cardinality value ended up in the cache policy. Diagnose it with the `X-Cache` response header CloudFront adds (`Hit from cloudfront` / `Miss from cloudfront`) and by comparing two requests that differ only in the suspect value: if both return the same body, the value is not in the key; if the origin logs show it missing entirely, it is in neither policy. ## The mental model to state in an interview "Cache policy equals key plus forwarded. Origin request policy equals forwarded only. Unnamed equals dropped." Then justify each value you place: does the body change with it, and how many distinct values exist?
- Your origin needs an Authorization header, but responses must still be shared across users — how do you configure that?Put `Authorization` in the **origin request policy** so it reaches the origin, and keep it out of the cache policy so it never enters the cache key. That only works if the response body is genuinely identical for every authorized caller; if it is user-specific, use a caching-disabled policy instead and let the origin serve it.
- What happens to hit rate if a session cookie ends up in the cache policy?The cache key becomes per-session, so each user populates their own copy of every object. Hit rate collapses toward zero, origin load rises to roughly what it was without a CDN, and you now also pay CloudFront request and transfer charges on top.
- How would you cache one variant per language without letting arbitrary query parameters explode the key?Use a whitelist rather than "all query strings": name only `lang` in the cache policy's query-string list. Campaign or analytics parameters then stay out of the key entirely, so `?lang=de&utm_source=x` and `?lang=de` share one cached object.
saying these in an interview costs you the question
- Thinks CloudFront forwards the whole viewer request by default
- Says the cache key is always just the URL path
- Puts Authorization or a session cookie in the cache policy
- Believes an origin request policy also creates separate cached copies
- Assumes a missing parameter is an origin bug rather than a stripped request