skip to content

In a CloudFront cache policy, what do the EnableAcceptEncodingGzip and EnableAcceptEncodingBrotli settings do, and why are they preferable to listing Accept-Encoding in the policy's header list?

level: middleimportance: nice to knowfreq 28%

answer

  1. raw header text has huge cardinality
  2. normalize to br, gzip, or nothing
  3. flags instead of the header list
  4. compression setting is a separate switch
  5. key the decision, not the string

basics

~20 s

Those settings make CloudFront normalize the viewer's Accept-Encoding down to gzip, br or nothing before using it in the cache key and the origin request, so a URL holds a few compressed variants instead of one per raw header string.

solid answer

~50 s

Browsers send wildly varying `Accept-Encoding` strings — different orders, different quality values, extra tokens. Putting that header in a cache policy's header list keys the cache on the raw string, so one URL fragments into dozens of near-identical cached objects and the hit rate falls for no benefit. Setting `EnableAcceptEncodingGzip` and `EnableAcceptEncodingBrotli` instead tells CloudFront to normalize: it reduces the header to `br`, `gzip` or removes it, uses that normalized value in the cache key, and forwards the normalized form to the origin. You end up with at most a small number of variants per URL. These settings also pair with the cache behavior's `Compress` option, which is what lets CloudFront compress an eligible origin response itself. The rule of thumb: use the two Accept-Encoding settings, and do not add `Accept-Encoding` to the header list as well.

go deeper

for a junior

Know that CloudFront can compress responses itself and that the cache has to keep compressed and uncompressed copies apart, which is what these settings are for.

for a middle

Explain the normalization precisely — br, then gzip, otherwise drop the header — and why keying on the raw Accept-Encoding string shatters the cache into near-identical objects.

for a senior

Show you can debug a compression complaint end to end: behaviour compression switch, cache policy settings, content type and size eligibility, and whether the origin already compressed the body.

for a principal

Generalize the rule you are applying: cache keys should carry normalized decisions rather than raw client strings, and that principle governs every header a team proposes adding to a key.

## The problem being solved Compressed and uncompressed bodies of the same URL are different bytes, so a cache that serves both must key on the encoding the viewer accepts. The naive way to do that in CloudFront is to add `Accept-Encoding` to the cache policy's header list. That works, and it is a trap. Real viewers do not send one canonical string. You will see `gzip, deflate, br`, `gzip, deflate, br, zstd`, `br;q=1.0, gzip;q=0.8, *;q=0.1`, `gzip`, and long tails from proxies and bots. Keyed raw, each distinct string is its own cached object holding an identical or near-identical body. One popular URL becomes dozens of cache entries, each warmed separately, each expiring separately, each a miss the first time. ## What the settings actually do `EnableAcceptEncodingGzip` and `EnableAcceptEncodingBrotli` live inside a cache policy's `ParametersInCacheKeyAndForwardedToOrigin` block. With them on, CloudFront **normalizes** the header before it does anything else: - viewer accepts Brotli and Brotli is enabled → cache key and origin request use `br` - otherwise, viewer accepts gzip and gzip is enabled → `gzip` - otherwise → the header is removed entirely So the number of encoding variants per URL is bounded by the settings you enabled, not by the creativity of user agents. This is normalization done for you at the exact place where it matters: the cache key. ```json "ParametersInCacheKeyAndForwardedToOrigin": { "EnableAcceptEncodingGzip": true, "EnableAcceptEncodingBrotli": true, "HeadersConfig": { "HeaderBehavior": "none" }, "CookiesConfig": { "CookieBehavior": "none" }, "QueryStringsConfig": { "QueryStringBehavior": "none" } } ``` Note the header list says `none` — the encoding is handled by the flags, not by listing the header. AWS's managed `CachingOptimized` policy is exactly this shape, which is why it is the sensible default for static assets. ## The relationship with CloudFront's own compression Two separate things are involved and candidates routinely merge them: 1. **The cache behavior's `Compress` setting** — whether CloudFront will compress an origin response itself before serving it. 2. **The cache policy's Accept-Encoding settings** — whether the encoding participates (normalized) in the cache key and the origin request. For CloudFront to compress on your behalf, the behaviour must have compression enabled, the cache policy must have the matching Accept-Encoding setting on, and the viewer must actually ask for that encoding. Beyond that, CloudFront compresses only eligible responses: compressible content types, a body within a size window (roughly one kilobyte up to about ten megabytes, as of 2025), a response that is not already compressed, and one whose size it can determine. If the origin already returns a compressed body with a `Content-Encoding`, CloudFront passes it through rather than recompressing — which is usually what you want, since the origin can compress at a higher effort level once and let the CDN store the result. ## Symptoms when this is wrong - **Low hit rate on assets that should be near-100%.** Check whether `Accept-Encoding` is in the header list; the cache is fragmenting per raw string. - **Responses arrive uncompressed despite compression being enabled.** Common causes: the content type is not on CloudFront's compressible list, the body is below or above the size window, the response lacks a determinable length, or the cache policy's Accept-Encoding setting is off so the encoding never reached the decision. - **A viewer gets a body encoded in a way it did not ask for.** That is the shape of a cache-key bug — some path is storing a compressed body under a key that did not record the encoding at all. ## What to say in an interview Frame it as a normalization argument, because that is the transferable idea: a cache key should record the *decision* a header implies, not the header's raw text. `Accept-Encoding` is the case where a CDN gives you that normalization as a first-class setting; other high-cardinality headers you have to normalize yourself before they reach the key.

  • You enable the Accept-Encoding settings but responses still come back uncompressed. What do you check?
    Whether the cache behavior's compression setting is on at all, whether the content type is one CloudFront compresses, whether the body falls inside the eligible size window, and whether the origin already set a Content-Encoding — in which case CloudFront passes its body through untouched instead of recompressing.
  • Why not just let the origin compress everything and skip these settings?
    That is a fine design — compress once at the origin at a high effort level and let CloudFront cache the compressed body. You still want the Accept-Encoding settings on so the cache key records which encoding is stored; otherwise a viewer that cannot accept Brotli could be served a Brotli body from cache.
  • What is the general lesson for other headers you are tempted to add to a cache key?
    Normalize before keying. A raw header's cardinality is what fragments the cache, so reduce it to the small set of decisions it actually implies — a device class rather than a full User-Agent, a language rather than a full Accept-Language list — and key on that.

saying these in an interview costs you the question

  • Adds the raw Accept-Encoding header to the cache policy header list
  • Thinks the Accept-Encoding settings alone make CloudFront compress
  • Assumes CloudFront recompresses bodies the origin already compressed
  • Believes every content type and size gets compressed
  • Confuses the cache behavior compression switch with the cache policy settings

context