BREAKING CHANGE: pre-compressed assets re-compressed at the edge

It seems due to a recent change pre-compressed assets, eg file.ext.br, are re-compressed at the edge, with an additional Content-Encoding header added, resulting in Content-Encoding: br, br. The browser receives double compressed data. This breaks existing applications.

relying on vercel edge compression, instead of pre-compressed assets, results in 30% larger file sizes as vercel is not using the maximum compression level.

As far as i can tell the change has not been announced or documented.

is there an option to disable this behaviour?
is there a bugfix planned to properly handle pre-compressed data?
why was this not announced or documented?

Hey, @azeitler! Welcome to the Vercel Community.

I can’t see anything that could have caused this change, but could you share an example with us? It’d be easier to show with side-by-side comparisons.

1 Like

Here you go: GitHub - azeitler/wasm-compression-issue

Starting at a 100kb file-size .br files are now compressed again and a second br Content-Encoding header is added resulting in a br, br Content-Encoding header, which Safari cannot handle (but Chrome can).

See this page:

This behaviour is new. Our logs show it started around July 30th.
Our last deploy previous to this regression was July 16th.

The change in behaviour is on Vercel’s side.

Using the edge compression provided by Vercel is not an option because it does not use maximum possible Brotli compression levels resulting in ~30% larger file sizes.

A related problem was reported in October 2024 🐛 Vercel not serving pre-compressed assets (brotli)
The user even provided a demo repository, but never received another answer.

@pawlean any update on this? Is this new default behaviour?

Safari still cannot handle the double encoding.

Hello, we will investigate this and update you!

Are there any updates on this @swarnava? We are running into the same issue - specifically for Unity Web builds that have .wasm.br / .framework.js.br / .data.br files compressed to Brotli, and Vercel always re-compresses them, which Safari specifically cannot handle and I am unable to find any workarounds while retaining Brotli compression. I tried setting the headers in vercel.json but no matter what I do, the files are always re-compressed by Vercel. Would be great if Vercel detected pre-compressed files automatically, or at least give as an option to manually disable compression.

@swarnava also jumping in here. Any news? The issue is still blocking us from Vercel for additional projects.

We have looked into this. Trying to get a confirmation by Monday.

Hi,

To follow up on this, if you request System.Private.CoreLib.wasm.br we’ll serve that pre-compressed file as-is. We don’t automatically recognize that System.Private.CoreLib.wasm.br is the pre-compressed version of System.Private.CoreLib.wasm, and we don’t auto-swap to it. I don’t think we do anything automatic like that.

To serve your pre-compressed Unity assets without Vercel re-compressing them, you can use rewrites with a has rule (Accept-Encoding: br) and set headers on the .br files. Example vercel.json:

{
"rewrites": [
{
"source": "/:name*.wasm",
"has": [{ "type": "header", "key": "Accept-Encoding", "value": ".br." }],
"destination": "/:name.wasm.br"
},
{
"source": "/:name*.framework.js",
"has": [{ "type": "header", "key": "Accept-Encoding", "value": ".br." }],
"destination": "/:name.framework.js.br"
},
{
"source": "/:name*.data",
"has": [{ "type": "header", "key": "Accept-Encoding", "value": ".br." }],
"destination": "/:name.data.br"
}
],
"headers": [
{
"source": "/(.)\.wasm\.br",
"headers": [
{ "key": "Content-Type", "value": "application/wasm" },
{ "key": "Content-Encoding", "value": "br" },
{ "key": "Cache-Control", "value": "public, max-age=31536000, immutable" },
{ "key": "Vary", "value": "Accept-Encoding" }
]
},
{
"source": "/(.)\.framework\.js\.br",
"headers": [
{ "key": "Content-Type", "value": "application/javascript; charset=utf-8" },
{ "key": "Content-Encoding", "value": "br" },
{ "key": "Cache-Control", "value": "public, max-age=31536000, immutable" },
{ "key": "Vary", "value": "Accept-Encoding" }
]
},
{
"source": "/(.*)\.data\.br",
"headers": [
{ "key": "Content-Type", "value": "application/octet-stream" },
{ "key": "Content-Encoding", "value": "br" },
{ "key": "Cache-Control", "value": "public, max-age=31536000, immutable" },
{ "key": "Vary", "value": "Accept-Encoding" }
]
}
]
}

Important notes:

  • Make sure the .br files are actually present in your output (e.g., in public/ or your static output directory).

  • Don’t set Content-Encoding: br on the non-.br paths; only set it on the .br files. With the rewrite + headers above, Vercel will serve the pre-compressed file and won’t re-compress it.

  • You can verify with:

    • curl -I -H “Accept-Encoding: br” https://your-domain/name.wasm

    • You should see Content-Encoding: br and the .br asset being served.

    • Also test without Accept-Encoding: br to ensure the uncompressed fallback works.

This approach should avoid Safari issues caused by double-compression while retaining Brotli for clients that support it. If you still see re-compression after this setup, please share a URL and we’ll inspect the response headers from the edge.

1 Like

Any news on my issue (because its different from @mihakrajnc’s and your answer does not cover it)

@swarnava Any news on my issue?
(because its different from @mihakrajnc’s and your answer does not cover it)