Developers & Technical · Guide · Developer Utilities
How to minify JavaScript
Minify JavaScript to shrink bundles and speed up loads—compare Terser, esbuild, and SWC instantly. Get free source map and integration tips, no sign-up required.
Minifying JavaScript shrinks bundle size, speeds up page loads, and reduces the bytes users download on slow connections. Done right, it’s invisible — same behavior, fewer kilobytes. Done wrong, it breaks your app in production. This guide covers what minification actually does (whitespace removal, variable renaming, dead code elimination), the difference between minification and compression, when to use Terser vs esbuild vs SWC, source maps for debugging minified code, the gotchas that break minified bundles, and how modern bundlers handle all of this automatically.
Advertisement
What minification actually does
A minifier reads your JavaScript source and outputs semantically equivalent but smaller code. The transformations include:
Whitespace removal: strip unnecessary spaces, tabs, and newlines. Typically saves 10-20%.
Variable renaming (mangling): rename totalUserCount to a. Works only on local scope variables, not exports or properties. Saves 30-50% on identifier-heavy code.
Dead code elimination: remove unreachable branches, unused imports, and dev-only code gated by process.env.NODE_ENV !== 'production'.
Constant folding: 2 + 3 becomes 5. "foo" + "bar" becomes "foobar".
Short-form rewrites: true becomes !0; undefined becomes void 0. Saves bytes, hurts readability — but readability doesn’t matter in production.
Minification vs compression
Minification and gzip/brotli are complementary, not redundant.
Minification removes redundancy visible to the JS parser.
Compression (gzip, brotli) removes redundancy visible to a byte-level algorithm.
Typical results: 100KB raw JS → 40KB minified → 12KB brotli. Both matter. Minification matters more for parse time (engine does less work on smaller input); compression matters more for transfer time.
Source maps — debug minified code
Minified code is unreadable. A source map maps minified positions back to original source, so browser devtools can show you the original file when debugging.
Inline: //# sourceMappingURL=data:application/json;base64,... embedded in the JS file. Increases file size; keep for dev only.
External: //# sourceMappingURL=app.js.map as a sibling file. Browser fetches only when devtools is open.
Hidden source maps: generate the map but don’t reference it in the JS. Upload to Sentry/Datadog/ Rollbar for error tracking without exposing source publicly.
Don’t ship source maps referencing public URLs unless you want source visible. Obvious, but common mistake.
Terser, esbuild, SWC — picking a minifier
Terser: the default for most bundlers. Written in JS, slow but produces the smallest output. Forked from UglifyJS, handles modern ES syntax.
esbuild: written in Go. 10-100x faster than Terser. Output is slightly larger (a few percent). Tradeoff is usually worth it for dev iteration speed.
SWC: Rust-based minifier used by Next.js and others. Fast like esbuild, output comparable to Terser. Now the default in most modern toolchains.
Rule: use whatever your bundler defaults to. The differences are small; the effort of switching rarely pays off.
Common breakages from minification
String-based property access: obj["longName"] vs obj.longName. Minifier mangles the latter to obj.a; leaves the string intact. Your code crashes.
Reflection on class/function names: SomeClass.name might return "a" after mangling. Affects routing/DI systems that rely on class names.
Angular-style DI with string params: older Angular code declared deps as strings matching function parameter names. Mangle breaks the match. Fixed by using array-form annotations or ngAnnotate.
Side-effectful module imports: tree shaking might drop imports that run code on load. sideEffects: false in package.json tells the bundler it’s safe to remove unused imports.
Dynamic eval: minified code inside eval can break if the evaluated code references symbols that got renamed. Avoid eval.
What minifiers can’t help with
Duplicated code: copy-pasted logic across files stays as two separate copies after minification (no dedup across scopes).
Large dependencies: importing moment.js costs ~70KB minified. Minifier can’t shrink third-party code you don’t own.
Tree shaking limits: only ESM imports tree shake cleanly. CommonJS require() is dynamic; bundler can’t always prove what’s unused.
Configuring minification
Most tuning happens through bundler config. Common Terser options worth knowing:
drop_console: remove console.log calls in production.
drop_debugger: strip debugger statements.
pure_funcs: mark functions as side-effect-free so calls get removed if return value unused.
reserved: names never to mangle (e.g., DI tokens, global API surfaces).
keep_classnames / keep_fnames: preserve names for reflection-based code.
Bundlers do this for you
Webpack: minifies in production mode by default with Terser.
Next.js / Vite / Parcel: minify production builds automatically.
esbuild: --minify flag or minify: true in config.
You rarely need to run a standalone minifier. The exception: you’re shipping a single file or inline script that isn’t part of a build pipeline.
Common mistakes
Shipping unminified code. Check your build output. If it’s readable, it’s not minified.
Shipping source maps publicly. Attackers can reverse-engineer your code. Use hidden source maps uploaded to an error-tracking service.
Minifying dev builds. Makes debugging painful. Use production mode only for production.
Forgetting to enable compression at the server.Minification without gzip/brotli leaves 70% of savings on the table.
Relying on class/function names for behavior.Minifier breaks this silently. Use explicit tokens or disable mangling selectively.
Run the numbers
Minify JavaScript instantly in your browser with the JS minifier. Pair with the CSS minifier for stylesheet shrinkage, and the HTML formatter to clean up markup before minifying.
Use these while you read
Tools that pair with this guide
- JavaScript MinifierShrink JS by stripping comments and whitespace fast in your browser—no accounts, just paste and minify instantly for free, with no sign-up.Developer Utilities
- CSS MinifierMinify your CSS online instantly by pasting it in to strip comments and whitespace for a smaller file. A free tool that keeps your data safe, no signup.Developer Utilities
- HTML FormatterFormat messy HTML into clean, indented code or compress it to a minified version instantly. A free, no-sign-up tool that runs safely in your browser.Developer Utilities
- JSON FormatterPaste JSON to beautify, validate, and minify with clear error messages, all in your browser without sign-up—free instant tool for developers.Developer Utilities
Advertisement
Continue reading
- Developers & TechnicalGitHub Actions Without Being a DevOps ExpertMaster GitHub Actions for the 90% use case with this practical playbook. Build, test, and deploy instantly using free common templates and no-sign-up guides.
- Developers & TechnicalBest Practices for Building Developer ToolsLearn CI/CD, IDE, and documentation standards for paid dev tools instantly. Implement best practices for what companies actually buy online.
- Developers & TechnicalHow to Contribute to Open Source Developer ToolsFind beginner-friendly OSS projects and ship your first pull request with confidence. Free, instant playbook to avoid mistakes and scale contributions.
- Developers & TechnicalHow to Design CLI Tools Developers LoveFree guide to build CLI tools developers actually love: composability, sensible defaults, human errors, trust by default, predictability, fast feedback.
- Developers & TechnicalPassword Security Guide with Real Entropy ExamplesCalculate real password entropy with 2026 attacker speeds. Free guide to diceware passphrases, password managers, and 2FA based on actual attack vectors.
- Developers & TechnicalJSON Format Rules Every Developer Should KnowFree guide to strict JSON spec rules, JSON5 vs JSONC, top 10 parser errors, Schema validation, streaming huge files, and security: prototype pollution.