Bundle Size Impact Calculator
Bundle Size Impact Calculator
Every npm install that adds 71.0 kB (24.4 kB gzip) of lodash to a client bundle costs every user real time on every page load[bundlephobia]. On a fast 50 Mbps fiber link that cost is 4 ms; on a 1.6 Mbps 3G link it is 122 ms of extra download before the first paint[chrome-lighthouse]. The difference between importing lodash and lodash/get is the difference between shipping a utility belt and shipping a single screwdriver — and the browser pays for the whole belt.
The mechanism is minification and compression. Source code is first minified — whitespace, comments, and long names stripped — which typically cuts 30–40% of bytes[wikipedia-minification]. The minified bundle is then compressed with gzip (DEFLATE) or brotli (modern, ~15–20% smaller than gzip) before it leaves the CDN[bundlephobia]. What finally travels over the wire is the compressed size, not the parsed size you see in your editor. A package that is 100 kB parsed may be 32 kB gzip and 26 kB brotli — still enough to push a performance budget over the 244 kB threshold where Lighthouse starts penalizing Time to Interactive[chrome-lighthouse].
This calculator translates the abstract "71 kB" into the concrete: parsed, minified, gzip, brotli, and the wall-clock download time on 3G (1.6 Mbps, 150 ms RTT), 4G (9 Mbps, 50 ms RTT), and WiFi (30 Mbps, 10 ms RTT)[grigorik-hpn]. It works in both directions: enter a parsed size in kilobytes and a gzip ratio, or pick a known package from the reference table. The result is dual-unit — KB and MB (1 MB = 1024 KB = 1,048,576 bytes)[nist-units] — and dual-compression, so a junior learning why import { get } from 'lodash' matters and a senior defending a budget in a PR review get the same answer without hand math. For the JavaScript module system behind tree-shaking, see MDN's modules guide[mdn-modules]; for splitting the result into lazy chunks, webpack's code-splitting guide shows the next step[webpack-code-splitting] and esbuild's API shows the fastest way to measure it[esbuild-api].
The calculator needs a size, a compression estimate, and a network speed. The worked examples below cover the three most common developer questions.
Example 1 — full lodash vs tree-shaken lodash/get: full import.
- Pick a package or enter a custom size. Select lodash (full) — parsed 71.0 kB (minified 24.4 kB gzip, 20.1 kB brotli)[bundlephobia]. Or type
71.0in Parsed Size (KB). - Choose import style. Leave Full import (71.0 kB). The calculator shows the alternative:
lodash/getis 7.2 kB parsed (2.9 kB gzip). - Enter gzip ratio if custom. For custom code, enter
0.34(24.4/71.0) for gzip and0.28for brotli — or leave the defaults0.32gzip /0.26brotli for unknown packages[wikipedia-minification]. - Press Calculate. Results: gzip 24.4 kB (0.024 MB), brotli 20.1 kB, 3G 122 ms, 4G 22 ms, WiFi 6 ms — and 29% of a 244 kB budget.
Example 2 — moment.js (the classic bundle bloat warning).
- Parsed 66.5 kB, gzip 19.8 kB[bundlephobia]. Calculate → brotli ~17.3 kB, 3G 99 ms. Replacing with
date-fns(19 kB parsed, 5.8 kB gzip) saves 14 kB gzip, or 70 ms on 3G — the kind of win that moves Lighthouse from 89 to 96.
Example 3 — your own component: 150 kB parsed, unknown compression.
Enter 150 KB, leave gzip 0.32 → gzip ~48 kB, brotli ~39 kB. On 3G that is 240 ms download; on 4G 43 ms. If your budget is 170 kB gzip, this single component is 28% of the budget — a candidate for React.lazy code-splitting[webpack-code-splitting].
Tips while entering:
- Use parsed size from Bundlephobia or
esbuild --bundle --metafile— not thepackage.jsonsizefield, which counts unbuilt source[esbuild-api]. - When comparing two packages, run the calculator twice and note the delta, not the absolute. The delta is the marginal cost of the choice.
All estimates are linear scalings of the parsed size. The only physics is bandwidth.
Let:
- S_parsed = parsed (or minified) size in kB
- r_gzip = gzip ratio (e.g., 0.32), r_brotli = brotli ratio (e.g., 0.26)
- B = bandwidth in Mbps (megabits per second), RTT = round-trip time in ms
- S_gzip, S_brotli = compressed sizes
Compressed sizes:
Download time (ideal, ignoring TCP slow-start, then plus RTT):
where S is in kB, ×8 converts to kilobits, B×1000 to kilobits per second, and RTT is in seconds. Example: 24.4 kB gzip on 1.6 Mbps 3G with 150 ms RTT:
The calculator reports both transfer time (122 ms) and with-RTT (272 ms) so you can see network latency vs bandwidth. Budget share:
where 244 kB is the common performance budget (Lighthouse "avoid enormous payloads")[chrome-lighthouse]. Unit conversion is exact: 1 kB = 1024 bytes, 1 MB = 1024 kB[nist-units].
Worked Step-Through
lodash full 71.0 kB, r_gzip 0.343 (24.4/71.0), r_brotli 0.283, 4G 9 Mbps, RTT 50 ms:
Tree-shaken lodash/get 7.2 kB → gzip 2.9 kB → T_4G 2.6 ms + 50 ms = 52.6 ms — a 19 ms saving per page load, or 19 seconds of aggregate user time per 1,000 page views.
Parsed, gzip, and brotli sizes for popular packages at their latest versions on Bundlephobia[bundlephobia]. All numbers are minified+gzipped as published; brotli estimated at 0.85× gzip where not published. Transfer time is gzip bytes over 1.6 Mbps 3G (no RTT) — add 150 ms RTT for wall-clock.
| lodash (full) | 71.0 | 24.4 | 20.1 | 122 | 10.0% |
| lodash/get | 7.2 | 2.9 | 2.5 | 15 | 1.2% |
| moment | 66.5 | 19.8 | 17.3 | 99 | 8.1% |
| date-fns (format) | 19.0 | 5.8 | 4.9 | 29 | 2.4% |
| react (18.2.0) | 42.2 | 12.0 | 10.2 | 60 | 4.9% |
| react-dom (18.2.0) | 130.0 | 42.0 | 35.7 | 210 | 17.2% |
| axios | 14.0 | 5.2 | 4.4 | 26 | 2.1% |
| three | 600.0 | 145.0 | 123.0 | 725 | 59.4% |
The delta tells the story: replacing moment with date-fns saves 14 kB gzip (70 ms on 3G); replacing lodash full with a single function saves 21.5 kB (107 ms). Do both in one PR and the median user on 3G loads 177 ms faster — enough to lift Lighthouse performance from orange to green[chrome-lighthouse].
-
Measure with the same tool you ship with.
esbuild --metafileandwebpack --jsonreport the minified size before gzip; Bundlephobia reports minified+gzipped[bundlephobia][esbuild-api]. Pick one and stick to it for comparisons — mixing parsed and minified inflates the delta. -
Tree-shake via named imports, not default.
import { get } from 'lodash'is not tree-shaken by default;import get from 'lodash/get'orimport { get } from 'lodash-es'is[webpack-code-splitting]. The reference table's 8× gap comes from this single syntax difference. -
Budget before you bloat. Set a
performance-budgetin Lighthouse CI: 244 kB gzip total, 130 kB per route[chrome-lighthouse]. The calculator's Budget% maps directly to that gate — if a new dependency pushes you over 10% of the budget alone, justify it in the PR description. -
Split, don't just shrink. A 145 kB
three.jsbelongs in aReact.lazychunk loaded on the 3D route, not in the main bundle[webpack-code-splitting]. Code-splitting keeps the initial gzip under budget even when the total app is large. -
Compare brotli when your CDN supports it. Cloudflare, Vercel, and Netlify serve brotli automatically; gzip-only math overstates cost by ~15%[bundlephobia]. Use the brotli column for the final budget check.
-
Watch the long tail of small packages. Five 5 kB gzip dependencies feel small individually but sum to 25 kB — 10% of the budget. Audit with
npx webpack-bundle-analyzeroresbuild --analyzebefore each major release. -
Document the cost in the PR. When you add a dependency, paste the calculator's result (gzip, brotli, 3G time, budget %) into the pull-request description. Future reviewers will see the trade-off without re-running the build, and the budget history lives in git.
- Estimates, not builds. The calculator multiplies a ratio; a real build's tree-shaking, scope hoisting, and minifier choices change the ratio per package[webpack-code-splitting]. Always confirm the final number with a production build.
- No runtime cost modeled. Parse and compile time correlates with parsed size, not gzip size, and varies by device CPU. A 600 kB
three.jshurts low-end mobiles more than the 725 ms transfer suggests[chrome-lighthouse]. - Network model is ideal. Real 3G/4G throughput fluctuates, TCP slow-start adds extra RTTs, and HTTP/2 multiplexing shares bandwidth. The calculator's
S×8/B + RTTis a useful floor, not a field measurement[grigorik-hpn]. - Gzip/brotli ratios are averages. Highly repetitive code compresses better than random data. The calculator's defaults (0.32 gzip, 0.26 brotli) are typical for JavaScript; a 0.40 ratio is possible for small, diverse bundles[wikipedia-minification].
- Budget threshold is conventional. 244 kB is a common Lighthouse budget but not a standard; your product's budget may be 170 kB or 500 kB depending on audience devices[chrome-lighthouse].
- ❓ What is the difference between parsed, gzip, and brotli sizes?
- ✅ Parsed is the minified JavaScript as executed by the browser. Gzip and brotli are compressed sizes that actually travel over the network — gzip via DEFLATE, brotli via a modern algorithm about 15 percent smaller. What the user downloads is the compressed size.
- ❓ Why does lodash full cost 8 times more than lodash/get?
- ✅ Full lodash bundles 300+ functions. Importing via 'lodash/get' or 'lodash-es' with tree-shaking lets the bundler include only the one function you use — 7.2 kB parsed versus 71 kB.
- ❓ Should I use gzip or brotli for budgeting?
- ✅ Use gzip for the conservative budget (all CDNs support it) and brotli for the optimistic check (most modern CDNs serve brotli). The calculator shows both.
- ❓ How do I find my package's parsed size?
- ✅ Check Bundlephobia for published packages, or build locally with esbuild --bundle --metafile or webpack --json and read the 'size' field. Use the minified size, not the source size.
- ❓ What is a good bundle budget?
- ✅ Lighthouse flags total gzip over about 244 kB. Many teams set 170 kB for the initial route and 500 kB total. The calculator's Budget% uses 244 kB as a reference.
- ❓ Does code-splitting reduce total bytes?
- ✅ No — it reduces initial bytes. Total bytes stay the same, but the initial route loads faster because heavy routes are lazy-loaded via React.lazy or dynamic import.
- ❓ Why does 3G time include RTT?
- ✅ Download time is transfer time plus round-trip latency. On 3G, RTT is about 150 ms, so even a tiny bundle takes at least 150 ms wall-clock. The calculator shows both transfer-only and with-RTT.
- ❓ Can I compare two packages directly?
- ✅ Yes — run the calculator twice with the same network settings and subtract the gzip sizes and times. The delta is the marginal cost of choosing one package over the other.
References
- [1]Bundlephobia. Find the cost of adding a npm package to your bundle.
- [2]webpack. Code Splitting Guide.
- [3]esbuild. API Documentation.
- [4]MDN Web Docs. JavaScript Modules Guide.
- [5]Wikipedia. Minification (programming).
- [6]Chrome for Developers. Lighthouse Performance Scoring.
- [7]National Institute of Standards and Technology (NIST). Metric (SI) Unit Conversion.
- [8]Grigorik, Ilya. High Performance Browser Networking. O'Reilly Media.Buy on Amazon
Last updated: August 22, 2026
UnByte — Independent Software Engineering
Every calculator references authoritative sources — Editorial policy
