Edge Compression & Asset Optimization

Cut bytes on the wire by negotiating the best compression codec per request at the CDN edge and re-encoding assets without round-tripping to origin.

Compression is the cheapest performance lever you control: it shrinks transfer size 60–80% for text payloads with near-zero origin cost, because the CDN does the work once and serves the encoded result from cache to every matching request. The hard part is not “turn on gzip” — it is negotiating the right codec via Accept-Encoding, keying the cache so a Brotli client never gets a gzip body (and vice versa), and never wasting CPU re-compressing already-compressed images or video. This guide covers the codec landscape (gzip, Brotli, Zstandard), the Vary: Accept-Encoding implication for your cache key, content-type targeting, minification, and image optimization across Cloudflare, AWS CloudFront, Fastly, and GCP.

Key implementation points:

  • Negotiate codec from the request Accept-Encoding header and emit Content-Encoding plus Vary: Accept-Encoding so caches stay correct.
  • Compress only compressible MIME types (HTML, CSS, JS, JSON, SVG, fonts); skip JPEG, PNG, WebP, MP4, and pre-.gz assets.
  • Store each encoding as a distinct cache variant so the hit ratio survives across mixed clients — see Cache Key & Vary Configuration.
  • Offload image re-encoding (Polish, CloudFront + Lambda@Edge, Fastly IO) and minification to the edge, and cache the optimized output.
Edge compression negotiation flow A request arrives with an Accept-Encoding header; the edge checks content type, then picks zstd, Brotli, gzip, or identity, and stores the result as a Vary variant. Request arrives Accept-Encoding: … Content-Type compressible? image/video? serve identity no yes → choose codec zstd best ratio/speed br (Brotli) smallest static gzip universal fallback identity none offered Emit Content-Encoding + Vary: Accept-Encoding Store as per-encoding cache variant

How edge compression works at the protocol level

Compression is a content negotiation dance defined by HTTP. The client advertises what it can decode in the Accept-Encoding request header, often with quality weights: Accept-Encoding: br;q=1.0, gzip;q=0.8, *;q=0.1. The server (or, at the edge, the CDN) picks one supported codec, compresses the body, and stamps the response with Content-Encoding: br. Critically it must also emit Vary: Accept-Encoding, which tells every downstream cache that the response body differs by the value of that request header. Without Vary, a shared cache can hand a Brotli-encoded body to a client that only sent Accept-Encoding: gzip, producing garbled output and ERR_CONTENT_DECODING_FAILED errors in browsers.

At the edge the negotiation usually happens twice. The browser-to-edge hop negotiates the codec the user actually receives. The edge-to-origin hop is a separate negotiation — most CDNs request Accept-Encoding: gzip (or nothing) from origin, then decompress and recompress at the edge so they can serve the smallest codec the client supports regardless of what origin produced. This is why turning on Brotli at a CDN works even when origin only knows gzip: the edge owns the final encode. It also means the encoded variant is what lands in the cache, and your effective hit ratio depends on how many encoding variants you fan out into — covered in depth under cache key and Vary configuration.

The interplay with TTL matters too. A compressed object and its freshness lifetime are independent: Cache-Control: max-age=31536000 governs how long the edge keeps each encoding variant, while Content-Encoding governs which bytes that variant holds. Set your freshness directives deliberately in Cache-Control & CDN TTL so highly compressible static assets (hashed JS/CSS bundles) get long immutable lifetimes and the expensive Brotli-11 encode amortizes across millions of hits.

Choosing a codec: gzip vs Brotli vs Zstandard

The three codecs occupy distinct points on the ratio-versus-CPU curve, and the right choice depends on whether the content is dynamic (encoded per response) or static (encoded once and cached).

  • gzip (DEFLATE) is the universal floor. Every HTTP client built in the last 25 years sends gzip in Accept-Encoding. It is fast to encode at levels 1–6 and decodes trivially. Use it as the guaranteed fallback and for dynamic responses where you cannot afford a heavy encode.
  • Brotli (br) wins on ratio for static text. At quality 11 it typically beats gzip by 15–25% on HTML/CSS/JS, but level-11 encoding is far too slow for per-request dynamic content — reserve it for cacheable assets where you pay the CPU once. For dynamic responses, Brotli quality 4–5 is a sweet spot that beats gzip-6 at comparable speed. Browser support for br is universal over HTTPS (Brotli is only advertised on TLS connections).
  • Zstandard (zstd) is the newest entrant, advertised by Chromium-based browsers since 2024 and by curl, CLIs, and service-to-service clients. Its key advantage is a wide, tunable speed/ratio range: at high levels it rivals Brotli’s ratio while decoding several times faster, which helps low-power clients. Support is not yet universal, so it must coexist with Brotli and gzip rather than replace them.
Codec trade-off matrix A four column matrix listing gzip level 6, Brotli quality 5, Brotli quality 11 and Zstandard level 19 against the transfer size each produces, the relative CPU cost of encoding, and which clients advertise the codec. Where each codec sits on the ratio-versus-CPU curve Codec / level Transfer size Encode cost Advertised by gzip -6 100% (baseline) 1x CPU every HTTP client brotli q5 92% 1.1x CPU all browsers over TLS brotli q11 78% 18x CPU all browsers over TLS zstd -19 79% 6x CPU Chromium 123+, curl

The practical rule: enable all three, let Accept-Encoding quality values and your CDN’s preference order decide, and always keep gzip as the safety net. A deep, provider-by-provider walkthrough of enabling the two modern codecs lives in Enabling Brotli and Zstandard Compression at the Edge.

Content-type targeting: what to compress and what to leave alone

Compression only helps entropy-rich text. Already-compressed binary formats — JPEG, PNG, WebP, AVIF, GIF, MP4, WebM, MP3, most PDFs, and pre-built .gz/.br artifacts — gain nothing and frequently grow slightly when run through DEFLATE, while burning CPU. Worse, re-compressing them risks double encoding (a .gz file served with an additional Content-Encoding: gzip), which breaks clients.

Target the compressible families explicitly. A safe allowlist: text/html, text/css, text/plain, text/xml, application/javascript, application/json, application/xml, image/svg+xml (SVG is text), application/wasm, and font formats font/ttf/font/otf (but not font/woff2, which is already Brotli-compressed internally). Most CDNs ship a default compressible-MIME list; verify it covers your API’s JSON and your SVG icons, and confirm it excludes image/* raster types.

Bytes on the wire by content type after Brotli Horizontal bars showing the transferred size of a one megabyte sample as a percentage of the original: HTML falls to twenty-two percent, JavaScript to twenty-nine, JSON to eighteen, SVG to twenty-four, while a PNG grows to one hundred and one percent. What Brotli q11 actually does to each content type 100% = uncompressed size text/html 22% application/javascript 29% application/json 18% image/svg+xml 24% image/png 101% The raster bar is the whole argument for a content-type allowlist: it costs CPU and adds bytes.

Provider-specific implementation

Cloudflare

Cloudflare compresses automatically based on content type and the client’s Accept-Encoding. Brotli is toggled in the dashboard (Speed → Optimization → Content Optimization) or via API, and zstd is negotiated automatically when the client supports it. For fine control, a Worker lets you override negotiation or compress responses your origin returns uncompressed:

export default {
  async fetch(request) {
    const res = await fetch(request);
    const ct = res.headers.get("content-type") || "";
    const accepts = request.headers.get("accept-encoding") || "";
    // Only touch compressible text; never raster images
    if (!/^(text\/|application\/(json|javascript|xml)|image\/svg)/.test(ct)) {
      return res;
    }
    const body = res.body;
    const headers = new Headers(res.headers);
    headers.set("vary", "accept-encoding");
    // Cloudflare's CompressionStream supports gzip + deflate; br/zstd are
    // handled by the platform layer when enabled.
    if (accepts.includes("gzip")) {
      headers.set("content-encoding", "gzip");
      return new Response(
        body.pipeThrough(new CompressionStream("gzip")),
        { status: res.status, headers }
      );
    }
    return new Response(body, { status: res.status, headers });
  }
};

Cloudflare Polish is the image counterpart: enable it (Speed → Optimization → Image Optimization) in Lossless or Lossy mode, and add WebP/AVIF conversion so the edge re-encodes raster images and serves the smallest format the browser’s Accept header allows. Image Resizing (/cdn-cgi/image/... or the cf.image Worker option) resizes and re-encodes on the fly, caching each variant.

Two Cloudflare behaviors catch people out. First, the zone toggle only governs what Cloudflare encodes itself: if your origin already returns Content-Encoding: gzip, the edge passes those bytes through untouched rather than decoding and re-encoding them, so a gzip-only origin quietly caps the ratio your visitors ever see. Have origin serve identity to the edge and let the platform own the final encode. Second, Compression Rules scope codec choice by expression — path, extension, or content type — which is the supported way to force br on a route the default MIME list skips, or to force identity on a text/event-stream endpoint. Rules evaluate before the response is written to cache, so whatever they select is the encoding that gets stored as the variant.

AWS CloudFront

CloudFront compresses objects when you enable Compress objects automatically on the cache behavior, the viewer sends Accept-Encoding: gzip or br, and the file matches a compressible content type within the 1 KB–10 MB size window. The cache policy must forward Accept-Encoding correctly — use the managed CachingOptimized policy, which normalizes the header into gzip/br flags so you do not blow up the cache key:

resource "aws_cloudfront_distribution" "site" {
  default_cache_behavior {
    target_origin_id       = "origin-app"
    viewer_protocol_policy = "redirect-to-https"
    compress               = true # gzip + Brotli auto-compression
    cache_policy_id        = data.aws_cloudfront_cache_policy.optimized.id
  }
}

data "aws_cloudfront_cache_policy" "optimized" {
  name = "Managed-CachingOptimized"
}

For image optimization, pair CloudFront with Lambda@Edge (or CloudFront Functions for lighter logic) on the origin-response event to resize/re-encode using sharp, then cache the result:

// Lambda@Edge origin-response: convert to WebP when the viewer accepts it
const sharp = require("sharp");
exports.handler = async (event) => {
  const res = event.Records[0].cf.response;
  const req = event.Records[0].cf.request;
  const accept = (req.headers["accept"]?.[0]?.value) || "";
  if (res.status === "200" && accept.includes("image/webp")) {
    const buf = Buffer.from(res.body, "base64");
    const webp = await sharp(buf).webp({ quality: 80 }).toBuffer();
    res.body = webp.toString("base64");
    res.bodyEncoding = "base64";
    res.headers["content-type"] = [{ key: "Content-Type", value: "image/webp" }];
    res.headers["vary"] = [{ key: "Vary", value: "Accept" }];
  }
  return res;
};

Fastly

Fastly does not auto-compress by default in the same way; you enable gzip via VCL or beta-fetch settings and target content types with set beresp.gzip. Brotli is supported at the edge for cacheable objects, and Fastly Image Optimizer (IO) handles raster re-encoding and resizing through URL query parameters:

sub vcl_fetch {
  # Compress text responses; never touch images/video
  if (beresp.http.Content-Type ~ "^(text/|application/(javascript|json|xml)|image/svg)") {
    set beresp.gzip = true;
  }
  # Ensure caches key on the encoding
  if (beresp.http.Content-Encoding) {
    set beresp.http.Vary = "Accept-Encoding";
  }
}

Fastly IO usage (?format=webp&width=800&quality=80) re-encodes at the edge and caches per-variant, with auto=webp letting the platform choose based on Accept.

Two details separate Fastly from the automatic platforms. set beresp.gzip = true marks the object for gzip only; Brotli lives in a separately stored br variant that the platform builds for cacheable objects, so a route marked pass never receives Brotli no matter what the client advertises. And because Vary participates in an object’s identity, adding Accept-Encoding to Vary in vcl_fetch after objects have already been hashed does not retroactively split what is in cache — you need a purge to rebuild the variant set. Fastly also reads Surrogate-Control independently of Cache-Control, which lets you hold a long edge lifetime for an expensively encoded asset while handing clients a much shorter freshness window.

Azure & GCP

Azure Front Door enables compression per route with a configurable content-type list and negotiates gzip/Brotli automatically. Google Cloud CDN compresses dynamic origin responses (gzip/Brotli) when dynamic compression is enabled on the backend service and caches each encoding separately. Both follow the same Vary: Accept-Encoding contract; the main operational difference is the compressible-type allowlist and the min/max object size thresholds.

The thresholds are where these two bite. Front Door only compresses objects inside a size band of roughly 1 KB to 8 MB and applies its type list per route, so a route inheriting the default list silently skips a custom MIME such as application/manifest+json until you add it explicitly. Google Cloud CDN draws a sharper line between backend services and backend buckets: dynamic compression is a backend-service feature, while a bucket serves exactly the bytes and metadata you uploaded. A bucket-backed site therefore needs .br and .gz objects uploaded alongside the identity copy, each carrying matching Content-Encoding metadata, because nothing in that path will encode on your behalf.

Codec and provider support matrix

Codec / Feature Best for Wire behavior Provider support / notes
gzip Dynamic + universal fallback Content-Encoding: gzip, decode everywhere All CDNs; always keep enabled
Brotli (br) Static text, smallest size Content-Encoding: br, HTTPS-only advertise Cloudflare, CloudFront, Fastly, Front Door, GCP
Zstandard (zstd) Fast decode, modern clients Content-Encoding: zstd, partial client support Cloudflare (auto); CloudFront/others limited
WebP / AVIF Raster image re-encode New Content-Type, Vary: Accept Polish, Lambda@Edge+sharp, Fastly IO
Minification JS/CSS/HTML byte reduction Same Content-Type, smaller body Cloudflare Auto Minify (deprecating — prefer build-time)

Step-by-step enablement procedure

  1. Inventory content types. Pull a sample of responses and group by Content-Type. Confirm your compressible allowlist covers HTML, CSS, JS, JSON, and SVG, and excludes raster images, video, woff2, and pre-compressed archives.
  2. Enable codecs at the edge. Turn on gzip and Brotli on every cache behavior/route; enable zstd where the provider offers it. Keep gzip enabled as the floor.
  3. Confirm Vary: Accept-Encoding. Ensure compressed responses carry the header so shared caches store per-encoding variants. Without it, mixed-client caches corrupt.
  4. Normalize the cache key. Use the provider’s managed policy (CloudFront CachingOptimized, Cloudflare default) so Accept-Encoding collapses to a small set of variants rather than every raw header string.
  5. Layer image optimization. Enable Polish/IO or wire a Lambda@Edge sharp step for WebP/AVIF, with Vary: Accept on those responses.
  6. Move minification to build time. Minify JS/CSS/HTML in your bundler (esbuild, Terser) rather than relying on edge auto-minify, which is being deprecated and can break inline scripts.
  7. Verify on the wire. Test each codec path:
# Request Brotli and confirm the edge honors it
curl -sI -H "Accept-Encoding: br" https://example.com/app.js | grep -i 'content-encoding\|vary'
# Force gzip
curl -sI -H "Accept-Encoding: gzip" https://example.com/app.js | grep -i content-encoding
# zstd-capable client
curl -sI -H "Accept-Encoding: zstd" https://example.com/app.js | grep -i content-encoding
# Confirm images are NOT re-compressed (expect no content-encoding)
curl -sI -H "Accept-Encoding: br,gzip" https://example.com/logo.png | grep -i content-encoding

Expected: the JS responses return content-encoding: br / gzip / zstd respectively with vary: accept-encoding; the PNG returns no content-encoding.

Measuring compression in production

Enablement is easy to fake. A toggle can read “on” while a third of your traffic still leaves the edge as identity because of a MIME gap, a size threshold, or a route that bypasses the cache. Three numbers turn the guesswork into evidence.

Coverage is the share of compressible responses that actually shipped encoded. Every major CDN exposes the response Content-Encoding (or an equivalent compression flag) in its log stream, so this is one group-by away:

# Cloudflare Logpush sample: encoding coverage grouped by content type
jq -r 'select(.EdgeResponseContentType | test("text/|json|javascript|svg"))
       | [.EdgeResponseContentType, (.EdgeResponseHeaderContentEncoding // "identity")]
       | @tsv' logs.json \
  | sort | uniq -c | sort -rn | head -20

A stubborn identity row against a text type means one of three things: the MIME is outside the allowlist, the object is under the minimum size, or the route is marked uncacheable and the platform declined to spend CPU on it.

Realized savings compares bytes actually billed against the identity size the origin would have shipped. Grouping edge response bytes by object class shows where the remaining fat is; a healthy configuration lands 70–80% off HTML, JS, and JSON and effectively nothing off media, which is exactly the shape you want.

Encoding mix is the split between br, zstd, gzip, and identity across live traffic. A sudden gzip spike usually means either a new client population that never negotiated TLS (so Brotli was never advertised) or an intermediary rewriting the request header — corporate proxies routinely normalize Accept-Encoding down to gzip or drop it altogether.

Wire a synthetic probe into monitoring so a regression fails loudly instead of surfacing weeks later as a slow creep in transfer bytes:

#!/usr/bin/env bash
set -euo pipefail
url="https://example.com/app.js"
hdrs=$(curl -sI -H 'Accept-Encoding: br, gzip' "$url")
enc=$(printf '%s' "$hdrs" | awk -F': ' 'tolower($1)=="content-encoding"{print $2}' | tr -d '\r')
vary=$(printf '%s' "$hdrs" | awk -F': ' 'tolower($1)=="vary"{print $2}' | tr -d '\r')
[ "$enc" = "br" ] || { echo "FAIL: expected br, got '${enc:-identity}'"; exit 1; }
printf '%s' "$vary" | grep -qi 'accept-encoding' || { echo "FAIL: Vary missing Accept-Encoding"; exit 1; }
echo "ok: encoding=$enc vary=$vary"

Run it per environment and per critical route rather than once against the homepage. The failures that matter in practice are almost always confined to a single cache behavior, a single path prefix, or a single content type — a homepage check will happily stay green through all of them.

Caching, Vary, and propagation implications

Every distinct Content-Encoding you serve is a separate object in the cache. Vary: Accept-Encoding is what makes that correct, but it also multiplies storage and can dilute hit ratio if the CDN keys on the raw header value instead of a normalized codec set. A client sending Accept-Encoding: gzip, deflate, br, zstd and another sending br, gzip should land on the same Brotli variant — that only happens if the CDN normalizes. CloudFront’s managed cache policies and Cloudflare’s default behavior do this for you; on Fastly or custom setups, normalize in VCL or your Worker before the lookup.

Because compressed objects are cached, changing your codec or compression level does not retroactively re-encode what is already stored. New encodings apply to fresh fetches. If you raise Brotli quality or switch a behavior from gzip to br, purge the affected paths so the edge re-fetches and re-encodes — invalidation procedure lives in your cache purging guide. Long max-age on hashed assets means an old gzip variant can linger for the full TTL otherwise.

Troubleshooting & rollback protocol

Symptom Likely cause Fix
ERR_CONTENT_DECODING_FAILED in browser Double compression (origin sent gzip, edge added br) Strip Content-Encoding at origin or disable edge compress for that path
Garbled body to some clients only Missing Vary: Accept-Encoding in shared cache Add Vary header; purge cache
Compression not applied Object outside size window or non-allowlisted MIME Check min/max size limits and add the content type
Images slightly larger Re-compressing already-compressed raster Exclude image/* raster types from compression
Low Brotli hit ratio Cache keyed on raw Accept-Encoding Normalize header to gzip/br/zstd set
.gz file served with extra encoding Compressing a pre-compressed artifact Set correct Content-Encoding at origin, exclude from edge compress

Rollback: if compression breaks a client segment, the fast revert is to disable the offending codec (usually a newly added Brotli or zstd toggle) on the cache behavior, leaving gzip active, then purge affected paths. Because gzip is universally decodable, this restores correctness immediately while you debug the Vary/double-encoding root cause.

Scenario: the hit ratio fell the week Brotli went on

The symptom is a cache hit ratio dropping ten to twenty points with no change in traffic mix, while origin egress climbs even though response bodies got smaller. The cause is nearly always variant fan-out. The edge is now storing one object per encoding, and if it keys on the raw Accept-Encoding string, every unusual ordering or quality-value permutation mints a brand-new object that must be fetched and encoded before it can ever serve a hit.

Diagnose it by counting distinct inbound header values in your logs:

jq -r '.ClientRequestHeaderAcceptEncoding // "none"' logs.json \
  | sort | uniq -c | sort -rn | head

Healthy output has three or four dominant rows carrying nearly all the traffic. A long list of dozens of near-identical strings means nothing is normalizing the header. The fix is either the provider’s own encoding flags, or a canonical rewrite before the cache lookup:

sub vcl_recv {
  if (req.http.Accept-Encoding ~ "br") {
    set req.http.Accept-Encoding = "br";
  } else if (req.http.Accept-Encoding ~ "gzip") {
    set req.http.Accept-Encoding = "gzip";
  } else {
    unset req.http.Accept-Encoding;
  }
}

After the change, purge the affected paths so the fragmented objects are rebuilt as a small canonical set — scope that purge narrowly, using the techniques in cache purging and invalidation, rather than emptying the zone. Expect the ratio to recover over roughly one full TTL cycle as the surviving variants warm, not instantly.

Edge cases & gotchas

  • woff2 is already Brotli inside. Compressing it again wastes CPU for ~0% gain — exclude it.
  • Brotli only over HTTPS. Browsers do not advertise br on plaintext HTTP, so testing over http:// will silently fall back to gzip.
  • Range requests + compression conflict. A Range request on a compressed object is ambiguous; most CDNs serve ranges only on identity encoding. Don’t expect byte-range resumes on Brotli bodies.
  • SSE / streaming. Buffered compression breaks Server-Sent Events and chunked streaming responses — disable compression for text/event-stream.
  • Content-Length vs Transfer-Encoding. Compressed streamed responses drop Content-Length; tooling that requires it must handle chunked transfer.
  • ETag changes per encoding. Some servers append -gzip to the ETag for compressed variants; weak ETags avoid false 304 mismatches across encodings.
  • Accept-Encoding can be stripped in transit. Corporate middleboxes and older load balancers rewrite or remove the header before it reaches the edge, so those users silently receive identity bodies. If one network or region shows anomalous transfer sizes, log the inbound header before blaming the CDN.
  • A hard-coded Content-Length breaks encoded paths. The length your application computes describes the identity body. If a framework pins it and the edge encodes afterwards, clients see truncated or hung responses — let the platform own the length header wherever encoding happens downstream.
  • Minification and compression are not substitutes. A compressor already models the whitespace and repeated identifiers a minifier removes, so stacking them buys perhaps two to five percent over compression alone. Minify for parse time and bundle hygiene, not for transfer size.
  • Brotli’s built-in dictionary favors markup. Its static dictionary is trained on web text, which is why the lead over gzip is widest on hand-written HTML and narrowest on minified bundles or machine-generated JSON. Do not assume one savings percentage generalizes across your content types.
  • Compression moves cost between billing lines. Egress is billed on the compressed bytes, but origin-fetch volume is billed on whatever the origin sent. An edge that pulls identity and encodes locally shifts spend rather than eliminating it — worth knowing before you quote a savings figure.
  • Test with a realistic request. A bare curl -I advertises no encodings at all and will happily report identity, convincing you compression is broken when it is working perfectly. Always pass an explicit Accept-Encoding.

Frequently Asked Questions

Should I compress at origin or at the edge? Prefer the edge for cacheable assets so the expensive Brotli-11 encode happens once and amortizes across all hits, and so the CDN can serve the smallest codec each client supports independent of origin. Origin compression makes sense only for uncacheable dynamic responses behind a CDN that won’t re-encode, but watch for double compression.

Why does my image get a little bigger when compressed? JPEG, PNG, WebP, and similar formats are already entropy-coded, so running DEFLATE or Brotli over them adds container overhead without removing redundancy. Exclude all raster image/* types from text compression and use a dedicated image optimizer (Polish, Fastly IO, Lambda@Edge) for those instead.

Is Zstandard ready to replace Brotli? Not yet for browser-facing static assets — zstd advertisement is still limited to newer Chromium clients and CLI tooling. Enable it alongside Brotli and gzip so capable clients benefit from its fast decode while everyone else falls back. It already shines for service-to-service and CLI download traffic.

Do I always need Vary: Accept-Encoding? Yes whenever a shared cache (CDN, proxy) stores compressed responses. Without it a cache can serve a Brotli body to a gzip-only client, causing decode failures. The header is what lets the cache store and select per-encoding variants correctly.

How should I handle streaming responses such as Server-Sent Events? Leave them uncompressed. Buffered compression withholds bytes until it has a block worth encoding, which defeats the purpose of a stream and can stall an SSE consumer for an unbounded time. Exclude text/event-stream and any chunked long-poll endpoint from the compressible list; individual events are small enough that the lost savings are negligible.

Does enabling three codecs triple my edge storage? Not meaningfully, because real traffic concentrates on one or two codecs and each encoded copy is a fraction of the original size. The genuine risk is cache-key fragmentation rather than volume: if the edge keys on the raw request header instead of a normalized codec token, you fan out into far more variants than the three you intended, and every one of them starts cold.

Back to CDN Caching & Performance Optimization