Article
Estimate File Sizes Instantly Before You Ship
You ship a bundle that looks fine in your editor, then Lighthouse hands you a 40-point penalty for oversized payloads. The file on disk and the bytes on the wire are two different numbers, and the gap is where your load time and your CDN bill quietly live. If you only ever look at the raw size, you are guessing at the metric that actually matters.
Payload size is not a cosmetic concern. Every kilobyte you send is time on a mobile radio, bytes metered by your CDN, and memory the browser has to parse. Getting the real compressed size in front of you before deploy is the cheapest performance win there is.
Gzip and Brotli: what compression actually buys you
Almost nothing ships uncompressed. Your server negotiates a compression algorithm with the browser via the Accept-Encoding header, and the response goes out smaller than the file on disk. Two algorithms dominate.
Gzip has been around since the 90s and is the safe default. It compresses fast, is supported literally everywhere, and gives solid ratios on text-based content like HTML, CSS, and JS. When you need to compress on the fly — dynamic API responses, server-rendered pages — gzip's speed wins.
Brotli is Google's newer algorithm. It uses a built-in dictionary and context modeling to squeeze text noticeably smaller than gzip, often 15-25% smaller on typical web assets. The catch is that its highest compression levels are slow, so it shines on static assets you compress once at build time and serve many times: bundles, fonts, precompiled CSS.
A rough rule of thumb:
| Content | Gzip | Brotli | |---|---|---| | Dynamic API responses, SSR pages | Better (fast to compress) | Too slow at high levels | | Static bundles, CSS, JS, fonts | Fine | Best ratio | | First-load-critical landing pages | Good | Best, precompress it | | Maximum browser compatibility | Always works | Works in every modern browser |
The practical takeaway: precompress static assets with Brotli at max level, let gzip handle anything generated per-request, and always measure the compressed number rather than the raw one.
Real-world size vs on-the-wire size
Here is the disconnect that trips people up. Your editor and your file system report the raw byte count. The browser downloads the compressed byte count. For text, the difference is large because natural language and code are highly repetitive — exactly what compressors exploit.
A representative JSON API response:
{
"users": [{ "id": "abc123", "name": "John" }, ...]
}
The same payload measured three ways:
- Raw: 42.1 KB
- Gzip: 12.3 KB
- Brotli: 10.7 KB
That 42 KB you see in your editor is not what your users download — they get roughly 11 KB. Optimizing against the raw number means you are tuning the wrong metric. Compressed size is what determines transfer time, and it is the only size worth budgeting against.
Where payloads secretly inflate
Not everything compresses well, and some habits actively bloat the wire.
- Base64. Encoding binary as base64 adds about 33% overhead by design, because it maps 3 bytes into 4 ASCII characters. An inline base64 image in your CSS is a third larger than the original file before compression even runs, and it blocks the stylesheet from being cached separately. If you want to see the exact overhead, drop a payload into the Base64 encoder and compare lengths.
- Images. Already-compressed formats like JPEG, PNG, and WebP barely shrink under gzip or Brotli — they are near-random bytes to a text compressor. Sending a 2 MB hero image and expecting compression to save you is wishful thinking; the fix is resizing and re-encoding, not gzip.
- JSON. Verbose and repetitive, so it compresses beautifully — but that is exactly why the raw size misleads you. A 500 KB JSON blob might go out as 40 KB. Judge it by the compressed number, not the scary raw one, before you reach for a binary format.
- Whitespace and duplicated keys. They inflate raw size but compress to almost nothing, so aggressive minification buys less than you would expect once compression is in play. Spend the effort on the payload's structure instead.
How to estimate size before you ship
You do not need to deploy, open DevTools, and read the Network tab to find out. Paste, upload, or drag a payload in and see raw, gzip, and Brotli side by side — text, JSON, images, or base64 blobs all handled the same way.
Drag & drop a file or
Fold this into your normal workflow:
- Validate config files before you push them to a CDN.
- Check the true weight of a large JSON response served from your API.
- Confirm your images are actually compressed and not just renamed.
- Catch a base64 logo that is silently bloating your CSS bundle.
Once you know the compressed number, you can set a real budget — for example, "no route ships more than 150 KB over the wire" — and check every change against it. If you are budgeting network cost more broadly, the file size estimator pairs well with measuring API response weight during development.
Key takeaways
- The size in your editor is the raw size; the browser downloads the compressed size, and they can differ by 3-4x for text.
- Use gzip for dynamic, compress-on-the-fly responses; precompress static assets with Brotli at max level for the best ratio.
- Base64 adds ~33% overhead before compression; already-compressed images barely shrink further — resize them instead of relying on gzip.
- JSON compresses extremely well, so always judge it by the compressed number, not the raw one.
- Estimate the on-the-wire size before you deploy and budget against it, rather than discovering bloat in production.
Stop guessing what your users download. Measure raw, gzip, and Brotli in one place with the file size estimator, set a payload budget, and keep every ship small and fast.