[{"data":1,"prerenderedAt":1161},["ShallowReactive",2],{"content:\u002Fnetwork-protocol-optimization\u002Fcompression-brotli-and-zstandard\u002Fzstandard-content-encoding-for-the-web":3,"surroundings:\u002Fnetwork-protocol-optimization\u002Fcompression-brotli-and-zstandard\u002Fzstandard-content-encoding-for-the-web":1152},{"id":4,"title":5,"body":6,"description":1132,"extension":1133,"meta":1134,"navigation":1145,"path":1146,"seo":1147,"stem":1150,"__hash__":1151},"content\u002Fnetwork-protocol-optimization\u002Fcompression-brotli-and-zstandard\u002Fzstandard-content-encoding-for-the-web\u002Findex.md","Zstandard Content-Encoding for the Web",{"type":7,"value":8,"toc":1114},"minimark",[9,13,41,44,145,150,183,187,193,199,205,211,215,220,413,417,434,595,599,615,619,630,767,771,778,782,785,897,901,904,908,911,915,941,945,951,960,966,972,976,988,997,1006,1015,1024,1033,1042,1051,1060,1072,1076,1099,1104,1107,1110],[10,11,5],"h1",{"id":12},"zstandard-content-encoding-for-the-web",[14,15,16,17,22,23,27,28,32,33,36,37,40],"p",{},"This guide is part of ",[18,19,21],"a",{"href":20},"\u002Fnetwork-protocol-optimization\u002Fcompression-brotli-and-zstandard\u002F","Compression: Brotli & Zstandard",", within ",[18,24,26],{"href":25},"\u002Fnetwork-protocol-optimization\u002F","Network & Server Response Optimization",". Zstandard (zstd) is a compression algorithm designed for speed: it compresses and decompresses much faster than Brotli at comparable ratios in the low and middle levels, and it scales from very fast to very strong compression. Chromium-based browsers and Firefox now accept ",[29,30,31],"code",{},"zstd"," as an HTTP ",[29,34,35],{},"Content-Encoding",", advertising it in ",[29,38,39],{},"Accept-Encoding",".",[14,42,43],{},"For static assets precompressed at build time, Brotli at level 11 still usually wins on size. Zstandard's advantage is in dynamic responses — server-rendered HTML and API JSON — where compression happens per request and CPU time adds to TTFB and server cost. There, zstd at levels 3–6 produces output close to Brotli 5–6 in size while using a fraction of the CPU, which matters for large responses and busy servers.",[14,45,46],{},[47,48,54,55,54,62,54,66,54,69,54,78,54,84,54,91,54,100,54,105,54,109,54,113,54,117,54,121,54,128,54,132,54,136,54,141,54],"svg",{"viewBox":49,"width":50,"role":51,"ariaLabel":52,"style":53},"0 0 760 194","100%","img","Bar chart of total CPU time to compress 1,000 server-rendered HTML responses with gzip, Brotli and zstd at typical dynamic levels.","height:auto;max-width:760px;display:block;margin:1.75rem auto;font-family:inherit;color:var(--fp-svg-ink)"," ",[56,57],"rect",{"className":58,"x":60,"y":60,"width":50,"height":50,"fill":61},[59],"svg-canvas","0","#ffffff",[63,64,65],"title",{},"Dynamic compression of 1,000 SSR responses (avg 220KB)",[67,68,52],"desc",{},[56,70],{"x":71,"y":71,"width":72,"height":73,"rx":74,"fill":75,"stroke":76,"style":77},"1","758","192","10","none","currentColor","stroke-opacity:0.18",[79,80,65],"text",{"x":81,"y":82,"fill":76,"style":83},"28.0","34.0","font-size:16px;font-weight:700",[79,85,90],{"x":86,"y":87,"fill":76,"style":88,"textAnchor":89},"72.6","70.0","font-size:13px","end","gzip 6",[56,92],{"x":93,"y":94,"width":95,"height":96,"rx":97,"fill":98,"stroke":98,"style":99},"84.6","56.0","192.8","19","3","#0466c8","fill-opacity:0.55;stroke-opacity:0.9",[79,101,104],{"x":102,"y":87,"fill":76,"style":103},"283.4","font-size:12px;font-weight:600","3.9s",[79,106,108],{"x":86,"y":107,"fill":76,"style":88,"textAnchor":89},"101.0","Brotli 5",[56,110],{"x":93,"y":111,"width":112,"height":96,"rx":97,"fill":98,"stroke":98,"style":99},"87.0","163.2",[79,114,116],{"x":115,"y":107,"fill":76,"style":103},"253.7","3.3s",[79,118,120],{"x":86,"y":119,"fill":76,"style":88,"textAnchor":89},"132.0","zstd 3",[56,122],{"x":93,"y":123,"width":124,"height":96,"rx":97,"fill":125,"stroke":126,"style":127},"118.0","44.5","#ffc300","#b8860b","fill-opacity:0.7;stroke-opacity:0.9",[79,129,131],{"x":130,"y":119,"fill":76,"style":103},"135.1","0.9s",[79,133,135],{"x":86,"y":134,"fill":76,"style":88,"textAnchor":89},"163.0","Brotli 9",[56,137],{"x":93,"y":138,"width":139,"height":96,"rx":97,"fill":75,"stroke":76,"style":140},"149.0","583.4","fill-opacity:0.7;stroke-opacity:0.35",[79,142,144],{"x":143,"y":134,"fill":76,"style":103},"674.0","11.8s",[146,147,149],"h2",{"id":148},"rapid-diagnosis","Rapid Diagnosis",[151,152,153,165,171,177],"ul",{},[154,155,156,162,163,40],"li",{},[157,158,159,160],"strong",{},"Check ",[29,161,39],{}," from your users' browsers in logs: count requests advertising ",[29,164,31],{},[154,166,167,170],{},[157,168,169],{},"Check server and CDN support"," for zstd output.",[154,172,173,176],{},[157,174,175],{},"Measure compression CPU"," for dynamic responses at your current settings.",[154,178,179,182],{},[157,180,181],{},"Compare sizes",": compress a sample of HTML and JSON responses with zstd and Brotli at candidate levels.",[146,184,186],{"id":185},"root-cause-analysis-why-consider-zstd","Root Cause Analysis: Why Consider zstd",[14,188,189,192],{},[157,190,191],{},"1. CPU cost of dynamic compression."," Large SSR pages compressed per request add CPU and TTFB.",[14,194,195,198],{},[157,196,197],{},"2. Size vs speed trade-off."," Brotli's best ratios come at slow levels unsuitable for dynamic content.",[14,200,201,204],{},[157,202,203],{},"3. High-traffic APIs."," JSON APIs with large payloads benefit from faster compression.",[14,206,207,210],{},[157,208,209],{},"4. Growing browser support."," A large share of users now accepts zstd.",[146,212,214],{"id":213},"step-by-step-resolution","Step-by-Step Resolution",[216,217,219],"h3",{"id":218},"_1-evaluate-on-your-own-responses","1. Evaluate on your own responses",[221,222,227],"pre",{"className":223,"code":224,"language":225,"meta":226,"style":226},"language-bash shiki shiki-themes github-light-high-contrast github-dark-high-contrast github-light-high-contrast","# Compare sizes and times on a saved HTML response.\nfor l in 3 6 9; do \u002Fusr\u002Fbin\u002Ftime -f \"zstd -$l %es\" zstd -q -$l -f -o page.zst page.html; ls -l page.zst | awk '{print $5}'; done\nfor q in 4 5 6; do \u002Fusr\u002Fbin\u002Ftime -f \"brotli -q $q %es\" brotli -f -q $q -o page.br page.html; ls -l page.br | awk '{print $5}'; done\n# trade-off: command-line timings include process startup; for small files, use\n# a benchmark harness in your server language for realistic numbers.\n","bash","",[29,228,229,238,331,401,407],{"__ignoreMap":226},[230,231,234],"span",{"class":232,"line":233},"line",1,[230,235,237],{"class":236},"sjfSM","# Compare sizes and times on a saved HTML response.\n",[230,239,241,245,249,252,256,259,262,265,268,272,276,279,282,285,288,291,294,296,298,301,304,307,309,312,315,317,320,323,326,328],{"class":232,"line":240},2,[230,242,244],{"class":243},"sPARh","for",[230,246,248],{"class":247},"saISM"," l ",[230,250,251],{"class":243},"in",[230,253,255],{"class":254},"sZ8jY"," 3",[230,257,258],{"class":254}," 6",[230,260,261],{"class":254}," 9",[230,263,264],{"class":247},"; ",[230,266,267],{"class":243},"do",[230,269,271],{"class":270},"sQw3B"," \u002Fusr\u002Fbin\u002Ftime",[230,273,275],{"class":274},"sPXB4"," -f",[230,277,278],{"class":254}," \"zstd -",[230,280,281],{"class":247},"$l",[230,283,284],{"class":254}," %es\"",[230,286,287],{"class":254}," zstd",[230,289,290],{"class":274}," -q",[230,292,293],{"class":274}," -",[230,295,281],{"class":247},[230,297,275],{"class":274},[230,299,300],{"class":274}," -o",[230,302,303],{"class":254}," page.zst",[230,305,306],{"class":254}," page.html",[230,308,264],{"class":247},[230,310,311],{"class":270},"ls",[230,313,314],{"class":274}," -l",[230,316,303],{"class":254},[230,318,319],{"class":243}," |",[230,321,322],{"class":270}," awk",[230,324,325],{"class":254}," '{print $5}'",[230,327,264],{"class":247},[230,329,330],{"class":243},"done\n",[230,332,334,336,339,341,344,347,349,351,353,355,357,360,363,365,368,370,372,375,378,381,383,385,387,389,391,393,395,397,399],{"class":232,"line":333},3,[230,335,244],{"class":243},[230,337,338],{"class":247}," q ",[230,340,251],{"class":243},[230,342,343],{"class":254}," 4",[230,345,346],{"class":254}," 5",[230,348,258],{"class":254},[230,350,264],{"class":247},[230,352,267],{"class":243},[230,354,271],{"class":270},[230,356,275],{"class":274},[230,358,359],{"class":254}," \"brotli -q ",[230,361,362],{"class":247},"$q",[230,364,284],{"class":254},[230,366,367],{"class":254}," brotli",[230,369,275],{"class":274},[230,371,290],{"class":274},[230,373,374],{"class":247}," $q ",[230,376,377],{"class":274},"-o",[230,379,380],{"class":254}," page.br",[230,382,306],{"class":254},[230,384,264],{"class":247},[230,386,311],{"class":270},[230,388,314],{"class":274},[230,390,380],{"class":254},[230,392,319],{"class":243},[230,394,322],{"class":270},[230,396,325],{"class":254},[230,398,264],{"class":247},[230,400,330],{"class":243},[230,402,404],{"class":232,"line":403},4,[230,405,406],{"class":236},"# trade-off: command-line timings include process startup; for small files, use\n",[230,408,410],{"class":232,"line":409},5,[230,411,412],{"class":236},"# a benchmark harness in your server language for realistic numbers.\n",[216,414,416],{"id":415},"_2-enable-zstd-with-fallbacks","2. Enable zstd with fallbacks",[14,418,419,420,422,423,426,427,430,431,433],{},"Configure the server or CDN to prefer ",[29,421,31],{}," when advertised, then ",[29,424,425],{},"br",", then ",[29,428,429],{},"gzip",". Many servers select based on the client's ",[29,432,39],{}," list and their own preference order.",[221,435,439],{"className":436,"code":437,"language":438,"meta":226,"style":226},"language-javascript shiki shiki-themes github-light-high-contrast github-dark-high-contrast github-light-high-contrast","\u002F\u002F Node.js sketch: choose encoding per request (zlib zstd support in recent Node versions).\nimport zlib from 'node:zlib';\nfunction pickEncoding(ae = '') {\n  if (ae.includes('zstd') && zlib.zstdCompress) return 'zstd';\n  if (ae.includes('br')) return 'br';\n  if (ae.includes('gzip')) return 'gzip';\n  return null;\n}\n\u002F\u002F trade-off: built-in zstd in Node.js is recent; on older runtimes use a native\n\u002F\u002F binding, or let a reverse proxy or CDN handle zstd instead.\n","javascript",[29,440,441,446,463,487,520,543,566,577,583,589],{"__ignoreMap":226},[230,442,443],{"class":232,"line":233},[230,444,445],{"class":236},"\u002F\u002F Node.js sketch: choose encoding per request (zlib zstd support in recent Node versions).\n",[230,447,448,451,454,457,460],{"class":232,"line":240},[230,449,450],{"class":243},"import",[230,452,453],{"class":247}," zlib ",[230,455,456],{"class":243},"from",[230,458,459],{"class":254}," 'node:zlib'",[230,461,462],{"class":247},";\n",[230,464,465,468,472,475,478,481,484],{"class":232,"line":333},[230,466,467],{"class":243},"function",[230,469,471],{"class":470},"smZ65"," pickEncoding",[230,473,474],{"class":247},"(",[230,476,477],{"class":270},"ae",[230,479,480],{"class":243}," =",[230,482,483],{"class":254}," ''",[230,485,486],{"class":247},") {\n",[230,488,489,492,495,498,500,503,506,509,512,515,518],{"class":232,"line":403},[230,490,491],{"class":243},"  if",[230,493,494],{"class":247}," (ae.",[230,496,497],{"class":470},"includes",[230,499,474],{"class":247},[230,501,502],{"class":254},"'zstd'",[230,504,505],{"class":247},") ",[230,507,508],{"class":243},"&&",[230,510,511],{"class":247}," zlib.zstdCompress) ",[230,513,514],{"class":243},"return",[230,516,517],{"class":254}," 'zstd'",[230,519,462],{"class":247},[230,521,522,524,526,528,530,533,536,538,541],{"class":232,"line":409},[230,523,491],{"class":243},[230,525,494],{"class":247},[230,527,497],{"class":470},[230,529,474],{"class":247},[230,531,532],{"class":254},"'br'",[230,534,535],{"class":247},")) ",[230,537,514],{"class":243},[230,539,540],{"class":254}," 'br'",[230,542,462],{"class":247},[230,544,546,548,550,552,554,557,559,561,564],{"class":232,"line":545},6,[230,547,491],{"class":243},[230,549,494],{"class":247},[230,551,497],{"class":470},[230,553,474],{"class":247},[230,555,556],{"class":254},"'gzip'",[230,558,535],{"class":247},[230,560,514],{"class":243},[230,562,563],{"class":254}," 'gzip'",[230,565,462],{"class":247},[230,567,569,572,575],{"class":232,"line":568},7,[230,570,571],{"class":243},"  return",[230,573,574],{"class":274}," null",[230,576,462],{"class":247},[230,578,580],{"class":232,"line":579},8,[230,581,582],{"class":247},"}\n",[230,584,586],{"class":232,"line":585},9,[230,587,588],{"class":236},"\u002F\u002F trade-off: built-in zstd in Node.js is recent; on older runtimes use a native\n",[230,590,592],{"class":232,"line":591},10,[230,593,594],{"class":236},"\u002F\u002F binding, or let a reverse proxy or CDN handle zstd instead.\n",[216,596,598],{"id":597},"_3-set-vary-and-cache-keys","3. Set Vary and cache keys",[14,600,601,602,605,606,608,609,611,612,614],{},"Send ",[29,603,604],{},"Vary: Accept-Encoding",", and make sure CDN caches store ",[29,607,31],{},", ",[29,610,425],{}," and ",[29,613,429],{}," variants separately (or normalise to these buckets).",[216,616,618],{"id":617},"_4-keep-static-assets-on-brotli-11","4. Keep static assets on Brotli 11",[14,620,621,622,625,626,629],{},"Precompressed static assets gain little from zstd; continue serving ",[29,623,624],{},".br"," files to browsers that accept Brotli. Optionally add ",[29,627,628],{},".zst"," files if your server prefers zstd.",[14,631,632],{},[47,633,54,636,54,639,54,642,54,644,54,661,54,664,54,666,54,672,54,679,54,683,54,688,54,696,54,702,54,706,54,712,54,715,54,718,54,721,54,724,54,727,54,730,54,733,54,736,54,739,54,743,54,745,54,748,54,751,54,754,54,758,54,761,54,764,54],{"viewBox":634,"width":50,"role":51,"ariaLabel":635,"style":53},"0 0 760 325","Decision sequence for selecting Content-Encoding for a response.",[56,637],{"className":638,"x":60,"y":60,"width":50,"height":50,"fill":61},[59],[63,640,641],{},"Which encoding to serve",[67,643,635],{},[645,646,647],"defs",{},[648,649,656],"marker",{"id":650,"viewBox":651,"refX":652,"refY":653,"markerWidth":654,"markerHeight":654,"orient":655},"fa4e3c6a60","0 0 10 10","9","5","7","auto-start-reverse",[657,658],"path",{"d":659,"fill":76,"style":660},"M0 0 L10 5 L0 10 z","fill-opacity:0.7",[56,662],{"x":71,"y":71,"width":72,"height":663,"rx":74,"fill":75,"stroke":76,"style":77},"323",[79,665,641],{"x":81,"y":82,"fill":76,"style":83},[56,667],{"x":81,"y":94,"width":668,"height":669,"rx":670,"fill":76,"stroke":76,"style":671},"320.0","35.0","6","fill-opacity:0.06;stroke-opacity:0.4",[79,673,678],{"x":674,"y":675,"fill":76,"style":676,"textAnchor":677},"188.0","78.0","font-size:13px;font-weight:700","middle","Is the response static and precompressed?",[56,680],{"x":681,"y":94,"width":668,"height":669,"rx":670,"fill":125,"stroke":126,"style":682},"412.0","fill-opacity:0.24;stroke-opacity:0.9",[79,684,687],{"x":685,"y":675,"fill":76,"style":686,"textAnchor":677},"572.0","font-size:12.5px","Serve br (level 11) if accepted",[232,689],{"x1":690,"y1":691,"x2":692,"y2":691,"stroke":76,"strokeWidth":693,"style":694,"markerEnd":695},"348.0","73.5","410.0","1.5","stroke-opacity:0.6","url(#fa4e3c6a60)",[79,697,701],{"x":698,"y":699,"fill":98,"style":700,"textAnchor":677},"380.0","66.5","font-size:11.5px;font-weight:700","yes",[232,703],{"x1":674,"y1":704,"x2":674,"y2":705,"stroke":76,"strokeWidth":693,"style":694,"markerEnd":695},"91.0","125.0",[79,707,711],{"x":708,"y":709,"fill":710,"style":700},"196.0","113.0","#51617a","no",[56,713],{"x":81,"y":714,"width":668,"height":669,"rx":670,"fill":76,"stroke":76,"style":671},"127.0",[79,716,717],{"x":674,"y":138,"fill":76,"style":676,"textAnchor":677},"Does the client accept zstd?",[56,719],{"x":681,"y":714,"width":668,"height":669,"rx":670,"fill":98,"stroke":98,"style":720},"fill-opacity:0.14;stroke-opacity:0.9",[79,722,723],{"x":685,"y":138,"fill":76,"style":686,"textAnchor":677},"Compress dynamically with zstd 3-6",[232,725],{"x1":690,"y1":726,"x2":692,"y2":726,"stroke":76,"strokeWidth":693,"style":694,"markerEnd":695},"144.5",[79,728,701],{"x":698,"y":729,"fill":98,"style":700,"textAnchor":677},"137.5",[232,731],{"x1":674,"y1":732,"x2":674,"y2":708,"stroke":76,"strokeWidth":693,"style":694,"markerEnd":695},"162.0",[79,734,711],{"x":708,"y":735,"fill":710,"style":700},"184.0",[56,737],{"x":81,"y":738,"width":668,"height":669,"rx":670,"fill":76,"stroke":76,"style":671},"198.0",[79,740,742],{"x":674,"y":741,"fill":76,"style":676,"textAnchor":677},"220.0","Does the client accept br?",[56,744],{"x":681,"y":738,"width":668,"height":669,"rx":670,"fill":98,"stroke":98,"style":720},[79,746,747],{"x":685,"y":741,"fill":76,"style":686,"textAnchor":677},"Compress dynamically with Brotli 4-5",[232,749],{"x1":690,"y1":750,"x2":692,"y2":750,"stroke":76,"strokeWidth":693,"style":694,"markerEnd":695},"215.5",[79,752,701],{"x":698,"y":753,"fill":98,"style":700,"textAnchor":677},"208.5",[232,755],{"x1":674,"y1":756,"x2":674,"y2":757,"stroke":76,"strokeWidth":693,"style":694,"markerEnd":695},"233.0","267.0",[79,759,711],{"x":708,"y":760,"fill":710,"style":700},"255.0",[56,762],{"x":81,"y":763,"width":668,"height":82,"rx":670,"fill":125,"stroke":126,"style":682},"269.0",[79,765,429],{"x":674,"y":766,"fill":76,"style":686,"textAnchor":677},"290.5",[146,768,770],{"id":769},"verification","Verification",[14,772,773,774,777],{},"Check response headers from a browser that supports zstd: ",[29,775,776],{},"content-encoding: zstd"," for dynamic HTML and JSON. Compare server CPU usage and TTFB for dynamic routes before and after. Verify that clients without zstd still receive Brotli or gzip, and that CDN caches do not mix variants.",[146,779,781],{"id":780},"worked-example-a-large-e-commerce-ssr-platform","Worked Example: A Large E-commerce SSR Platform",[14,783,784],{},"An e-commerce platform server-rendered category pages averaging 310KB of HTML, compressed with Brotli level 6 at the origin. Compression accounted for 12% of server CPU and about 9ms of TTFB per request. Enabling zstd level 4 for browsers advertising it (about 70% of traffic) reduced compression CPU for those requests by 75%, saving 6–7ms of TTFB at p75 and allowing the team to reduce server instances by 8%. Transferred sizes were within 3% of Brotli 6. Brotli remained the fallback, and static assets continued to use precompressed Brotli 11.",[14,786,787],{},[47,788,54,791,54,794,54,797,54,799,54,802,54,804,54,808,54,815,54,819,54,823,54,826,54,830,54,834,54,838,54,840,54,844,54,846,54,849,54,852,54,856,54,858,54,860,54,862,54,864,54,867,54,871,54,873,54,876,54,878,54,881,54,884,54,888,54,890,54,892,54,894,54],{"viewBox":789,"width":50,"role":51,"ariaLabel":790,"style":53},"0 0 760 228","Recommended encoding by response type when Brotli and zstd are both available.",[56,792],{"className":793,"x":60,"y":60,"width":50,"height":50,"fill":61},[59],[63,795,796],{},"Where zstd fits",[67,798,790],{},[56,800],{"x":71,"y":71,"width":72,"height":801,"rx":74,"fill":75,"stroke":76,"style":77},"226",[79,803,796],{"x":81,"y":82,"fill":76,"style":83},[56,805],{"x":81,"y":94,"width":806,"height":807,"rx":60,"fill":76,"stroke":76,"style":671},"171.6","30.0",[79,809,814],{"x":810,"y":811,"fill":76,"style":812,"textAnchor":813},"38.0","75.5","font-size:12.5px;font-weight:700","start","Response",[56,816],{"x":817,"y":94,"width":818,"height":807,"rx":60,"fill":76,"stroke":76,"style":671},"199.6","266.2",[79,820,822],{"x":821,"y":811,"fill":76,"style":812,"textAnchor":677},"332.7","Preferred",[56,824],{"x":825,"y":94,"width":818,"height":807,"rx":60,"fill":76,"stroke":76,"style":671},"465.8",[79,827,829],{"x":828,"y":811,"fill":76,"style":812,"textAnchor":677},"598.9","Fallback",[56,831],{"x":81,"y":832,"width":806,"height":807,"rx":60,"fill":75,"stroke":76,"style":833},"86.0","stroke-opacity:0.35",[79,835,837],{"x":810,"y":836,"fill":76,"style":812,"textAnchor":813},"105.5","Hashed static JS and CSS",[56,839],{"x":817,"y":832,"width":818,"height":807,"rx":60,"fill":98,"stroke":98,"style":720},[79,841,843],{"x":821,"y":836,"fill":76,"style":842,"textAnchor":677},"font-size:12px","Brotli 11 precompressed",[56,845],{"x":825,"y":832,"width":818,"height":807,"rx":60,"fill":75,"stroke":76,"style":833},[79,847,848],{"x":828,"y":836,"fill":76,"style":842,"textAnchor":677},"gzip 9",[56,850],{"x":81,"y":851,"width":806,"height":807,"rx":60,"fill":75,"stroke":76,"style":833},"116.0",[79,853,855],{"x":810,"y":854,"fill":76,"style":812,"textAnchor":813},"135.5","Static HTML from SSG",[56,857],{"x":817,"y":851,"width":818,"height":807,"rx":60,"fill":98,"stroke":98,"style":720},[79,859,843],{"x":821,"y":854,"fill":76,"style":842,"textAnchor":677},[56,861],{"x":825,"y":851,"width":818,"height":807,"rx":60,"fill":75,"stroke":76,"style":833},[79,863,848],{"x":828,"y":854,"fill":76,"style":842,"textAnchor":677},[56,865],{"x":81,"y":866,"width":806,"height":807,"rx":60,"fill":75,"stroke":76,"style":833},"146.0",[79,868,870],{"x":810,"y":869,"fill":76,"style":812,"textAnchor":813},"165.5","SSR HTML per request",[56,872],{"x":817,"y":866,"width":818,"height":807,"rx":60,"fill":98,"stroke":98,"style":720},[79,874,875],{"x":821,"y":869,"fill":76,"style":842,"textAnchor":677},"zstd 3-6",[56,877],{"x":825,"y":866,"width":818,"height":807,"rx":60,"fill":75,"stroke":76,"style":833},[79,879,880],{"x":828,"y":869,"fill":76,"style":842,"textAnchor":677},"Brotli 4-5 then gzip",[56,882],{"x":81,"y":883,"width":806,"height":807,"rx":60,"fill":75,"stroke":76,"style":833},"176.0",[79,885,887],{"x":810,"y":886,"fill":76,"style":812,"textAnchor":813},"195.5","Large JSON APIs",[56,889],{"x":817,"y":883,"width":818,"height":807,"rx":60,"fill":98,"stroke":98,"style":720},[79,891,120],{"x":821,"y":886,"fill":76,"style":842,"textAnchor":677},[56,893],{"x":825,"y":883,"width":818,"height":807,"rx":60,"fill":75,"stroke":76,"style":833},[79,895,896],{"x":828,"y":886,"fill":76,"style":842,"textAnchor":677},"Brotli 4 then gzip",[146,898,900],{"id":899},"zstd-in-the-wider-picture","zstd in the Wider Picture",[14,902,903],{},"Compression algorithm choice is a refinement. The biggest wins remain: compressing everything compressible at all, caching HTML so it is compressed once rather than per request, precompressing static assets at maximum levels, and shipping fewer bytes in the first place. Zstandard matters most for platforms with large dynamic responses and significant compression CPU. For a typical small site behind a CDN that compresses at the edge, enabling Brotli is the important step, and zstd can follow when the CDN supports it.",[146,905,907],{"id":906},"rolling-out-zstd-safely","Rolling Out zstd Safely",[14,909,910],{},"Introduce zstd gradually. Enable it on a single dynamic route or a share of traffic, and compare three things against the Brotli control: response sizes, server CPU per request, and TTFB at p75 and p95. Watch error logs for decoding failures, which usually point to an intermediary that mishandles the unfamiliar encoding. Because the browser only receives zstd when it advertises support, and every other client keeps getting Brotli or gzip, rollback is a single configuration change.",[146,912,914],{"id":913},"common-mistakes","Common Mistakes",[151,916,917,923,929,935],{},[154,918,919,922],{},[157,920,921],{},"Replacing Brotli for static assets."," Brotli 11 usually produces smaller static files.",[154,924,925,928],{},[157,926,927],{},"Forgetting fallbacks."," Clients without zstd must still get Brotli or gzip.",[154,930,931,934],{},[157,932,933],{},"Missing Vary."," Caches could serve zstd to clients that cannot decode it.",[154,936,937,940],{},[157,938,939],{},"High zstd levels on the fly."," Levels above about 12 lose the speed advantage.",[146,942,944],{"id":943},"edge-cases","Edge Cases",[14,946,947,950],{},[157,948,949],{},"Window size limits."," Browsers limit the zstd window size they accept; standard server configurations stay within it.",[14,952,953,956,957,959],{},[157,954,955],{},"Intermediary support."," Older proxies may not recognise ",[29,958,31],{}," and could mishandle it; test through your full delivery path.",[14,961,962,965],{},[157,963,964],{},"Streaming."," zstd supports streaming compression; flush per chunk for streaming SSR.",[14,967,968,971],{},[157,969,970],{},"Dictionaries."," zstd also supports dictionaries; see compression dictionary transport for the web standard.",[146,973,975],{"id":974},"faq","FAQ",[977,978,981,985],"details",{"className":979},[980],"faq-item",[982,983,984],"summary",{},"Which browsers support zstd Content-Encoding?",[14,986,987],{},"Chromium-based browsers and Firefox support it. Check current support data for Safari and others, and always keep fallbacks.",[977,989,991,994],{"className":990},[980],[982,992,993],{},"Is zstd better than Brotli?",[14,995,996],{},"For dynamic compression speed at similar ratios, often yes. For maximum compression of static assets, Brotli 11 usually produces smaller files.",[977,998,1000,1003],{"className":999},[980],[982,1001,1002],{},"What zstd level should I use?",[14,1004,1005],{},"Levels 3–6 for dynamic responses give a good balance. Higher levels slow down quickly without large size gains for typical web responses.",[977,1007,1009,1012],{"className":1008},[980],[982,1010,1011],{},"Does zstd decompress faster in the browser?",[14,1013,1014],{},"zstd decompression is very fast, but Brotli and gzip decompression are also fast enough that client-side differences are rarely noticeable.",[977,1016,1018,1021],{"className":1017},[980],[982,1019,1020],{},"Do CDNs support zstd?",[14,1022,1023],{},"Support is growing; some CDNs compress with zstd at the edge or pass through origin zstd responses. Check your provider's documentation.",[977,1025,1027,1030],{"className":1026},[980],[982,1028,1029],{},"Can I serve zstd over HTTP\u002F1.1?",[14,1031,1032],{},"Content-Encoding is independent of the HTTP version, but browsers generally only advertise newer encodings over HTTPS.",[977,1034,1036,1039],{"className":1035},[980],[982,1037,1038],{},"Should API responses use zstd?",[14,1040,1041],{},"Large JSON responses are a good fit: they compress very well and benefit from fast compression on busy API servers.",[977,1043,1045,1048],{"className":1044},[980],[982,1046,1047],{},"Does zstd help Core Web Vitals directly?",[14,1049,1050],{},"Slightly, through lower TTFB on dynamic responses when compression time was significant. Its larger benefit is often reduced server CPU, which keeps latency stable under load.",[977,1052,1054,1057],{"className":1053},[980],[982,1055,1056],{},"Will search engine crawlers accept zstd?",[14,1058,1059],{},"Crawlers advertise the encodings they support; serve them whatever they accept, falling back to gzip.",[977,1061,1063,1066],{"className":1062},[980],[982,1064,1065],{},"Can zstd be precompressed too?",[14,1067,1068,1069,1071],{},"Yes. Static ",[29,1070,628],{}," files can be generated at build time and served to clients that accept zstd, although Brotli 11 is usually smaller for static text.",[146,1073,1075],{"id":1074},"related","Related",[151,1077,1078,1085,1092],{},[154,1079,1080,1084],{},[18,1081,1083],{"href":1082},"\u002Fnetwork-protocol-optimization\u002Fcompression-brotli-and-zstandard\u002Fenabling-brotli-on-nginx-and-cdns\u002F","Enabling Brotli on nginx and CDNs"," — the main fallback.",[154,1086,1087,1091],{},[18,1088,1090],{"href":1089},"\u002Fnetwork-protocol-optimization\u002Fcompression-brotli-and-zstandard\u002Fcompression-dictionary-transport\u002F","Compression dictionary transport"," — dictionaries with zstd and Brotli.",[154,1093,1094,1098],{},[18,1095,1097],{"href":1096},"\u002Fnetwork-protocol-optimization\u002Ftime-to-first-byte-optimization\u002Fdiagnosing-slow-ttfb-with-server-timing\u002F","Diagnosing slow TTFB with Server-Timing"," — measure compression time.",[1100,1101,1103],"script",{"type":1102},"application\u002Fld+json","\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"HowTo\",\n  \"name\": \"Zstandard Content-Encoding for the Web\",\n  \"description\": \"What Zstandard brings to HTTP compression, where it beats Brotli, how to serve it with fallbacks, and how to measure the effect.\",\n  \"step\": [\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 1,\n      \"name\": \"Evaluate on your own responses\",\n      \"text\": \"Evaluate on your own responses\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 2,\n      \"name\": \"Enable zstd with fallbacks\",\n      \"text\": \"Configure the server or CDN to prefer zstd when advertised, then br, then gzip.\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 3,\n      \"name\": \"Set Vary and cache keys\",\n      \"text\": \"Send Vary: Accept-Encoding, and make sure CDN caches store zstd, br and gzip variants separately (or normalise to these buckets).\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 4,\n      \"name\": \"Keep static assets on Brotli 11\",\n      \"text\": \"Precompressed static assets gain little from zstd; continue serving .br files to browsers that accept Brotli.\"\n    }\n  ]\n}\n",[1100,1105,1106],{"type":1102},"\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"TechArticle\",\n  \"headline\": \"Zstandard Content-Encoding for the Web\",\n  \"description\": \"What Zstandard brings to HTTP compression, where it beats Brotli, how to serve it with fallbacks, and how to measure the effect.\",\n  \"datePublished\": \"2026-10-06\",\n  \"dateModified\": \"2026-10-06\",\n  \"author\": {\n    \"@type\": \"Organization\",\n    \"name\": \"frontend-performance.com\"\n  },\n  \"publisher\": {\n    \"@type\": \"Organization\",\n    \"name\": \"frontend-performance.com\"\n  },\n  \"mainEntityOfPage\": {\n    \"@type\": \"WebPage\",\n    \"@id\": \"https:\u002F\u002Ffrontend-performance.com\u002Fnetwork-protocol-optimization\u002Fcompression-brotli-and-zstandard\u002Fzstandard-content-encoding-for-the-web\u002F\"\n  }\n}\n",[1100,1108,1109],{"type":1102},"\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"BreadcrumbList\",\n  \"itemListElement\": [\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 1,\n      \"name\": \"Home\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 2,\n      \"name\": \"Network & Server Response Optimization\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fnetwork-protocol-optimization\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 3,\n      \"name\": \"Compression: Brotli & Zstandard\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fnetwork-protocol-optimization\u002Fcompression-brotli-and-zstandard\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 4,\n      \"name\": \"Zstandard Content-Encoding for the Web\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fnetwork-protocol-optimization\u002Fcompression-brotli-and-zstandard\u002Fzstandard-content-encoding-for-the-web\u002F\"\n    }\n  ]\n}\n",[1111,1112,1113],"style",{},"html pre.shiki code .sjfSM, html code.shiki .sjfSM{--shiki-default:#66707B;--shiki-dark:#BDC4CC;--shiki-light:#66707B}html pre.shiki code .sPARh, html code.shiki .sPARh{--shiki-default:#A0111F;--shiki-dark:#FF9492;--shiki-light:#A0111F}html pre.shiki code .saISM, html code.shiki .saISM{--shiki-default:#0E1116;--shiki-dark:#F0F3F6;--shiki-light:#0E1116}html pre.shiki code .sZ8jY, html code.shiki .sZ8jY{--shiki-default:#032563;--shiki-dark:#ADDCFF;--shiki-light:#032563}html pre.shiki code .sQw3B, html code.shiki .sQw3B{--shiki-default:#702C00;--shiki-dark:#FFB757;--shiki-light:#702C00}html pre.shiki code .sPXB4, html code.shiki .sPXB4{--shiki-default:#023B95;--shiki-dark:#91CBFF;--shiki-light:#023B95}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html pre.shiki code .smZ65, html code.shiki .smZ65{--shiki-default:#622CBC;--shiki-dark:#DBB7FF;--shiki-light:#622CBC}",{"title":226,"searchDepth":240,"depth":240,"links":1115},[1116,1117,1118,1124,1125,1126,1127,1128,1129,1130,1131],{"id":148,"depth":240,"text":149},{"id":185,"depth":240,"text":186},{"id":213,"depth":240,"text":214,"children":1119},[1120,1121,1122,1123],{"id":218,"depth":333,"text":219},{"id":415,"depth":333,"text":416},{"id":597,"depth":333,"text":598},{"id":617,"depth":333,"text":618},{"id":769,"depth":240,"text":770},{"id":780,"depth":240,"text":781},{"id":899,"depth":240,"text":900},{"id":906,"depth":240,"text":907},{"id":913,"depth":240,"text":914},{"id":943,"depth":240,"text":944},{"id":974,"depth":240,"text":975},{"id":1074,"depth":240,"text":1075},"What Zstandard brings to HTTP compression, where it beats Brotli, how to serve it with fallbacks, and how to measure the effect.","md",{"slug":12,"type":1135,"breadcrumb":1136,"datePublished":1144,"dateModified":1144},"article",[1137,1140,1141,1142],{"name":1138,"url":1139},"Home","\u002F",{"name":26,"url":25},{"name":21,"url":20},{"name":5,"url":1143},"\u002Fnetwork-protocol-optimization\u002Fcompression-brotli-and-zstandard\u002Fzstandard-content-encoding-for-the-web\u002F","2026-10-06",true,"\u002Fnetwork-protocol-optimization\u002Fcompression-brotli-and-zstandard\u002Fzstandard-content-encoding-for-the-web",{"title":1148,"description":1149},"Zstandard (zstd) Content-Encoding for the Web","Zstandard compresses dynamic HTML and JSON several times faster than Brotli at similar ratios. Learn browser support, server setup, levels and safe fallbacks.","network-protocol-optimization\u002Fcompression-brotli-and-zstandard\u002Fzstandard-content-encoding-for-the-web\u002Findex","Vj4qrNBwOX6CC4QGQwDNIuMCk25tKYXOnSOuI6iHLNw",[1153,1157],{"title":1154,"path":1155,"stem":1156,"children":-1},"Precompressing Static Assets at Build Time","\u002Fnetwork-protocol-optimization\u002Fcompression-brotli-and-zstandard\u002Fprecompressing-static-assets-at-build-time","network-protocol-optimization\u002Fcompression-brotli-and-zstandard\u002Fprecompressing-static-assets-at-build-time\u002Findex",{"title":1158,"path":1159,"stem":1160,"children":-1},"HTTP\u002F2, HTTP\u002F3 & Connection Management","\u002Fnetwork-protocol-optimization\u002Fhttp2-http3-and-connection-management","network-protocol-optimization\u002Fhttp2-http3-and-connection-management\u002Findex",1791308073461]