Minifying JavaScript is the cheapest performance win in a web project. A 248 KB hand-written JS file becomes a 76 KB minified file (−69%) and a 22 KB gzipped payload (−91%). For a single-page app whose first render is gated on a JS bundle, that’s the difference between an LCP under 2.5 seconds and a sluggish first paint. Build tools like webpack, Vite, and Next.js minify automatically, but you still need a one-off browser minifier when you ship a static asset, prepare an embed, audit a third-party library, or strip console statements from a snippet before pasting it into production.
Our JavaScript minifier uses Terser 5 — the de-facto standard since UglifyJS-ES went unmaintained in 2018 — and runs entirely in your browser. ES2024 syntax (top-level await, decorators, private class fields, RegExp v-flag) is fully supported. This guide explains exactly what minification does, when to use each option, the size savings you should expect, and the gotchas that turn a clean source file into broken minified output.
What minification actually does (and doesn’t)
| Transformation | Savings | Risk? |
|---|---|---|
| Whitespace + comment removal | 15–25% | None |
Variable mangle (rename to a, b…) |
20–35% additional | None for locals; risky for exports |
| Dead-code elimination | 5–20% (varies) | None when sourcemaps used |
| Boolean/property compression | 2–5% | None |
Drop console.* statements |
1–3% | Loses debug visibility |
Property mangle (obj.foo → obj.a) |
10–20% additional | High — breaks JSON/runtime keys |
The default Terser preset gives you the first 5 transforms safely. Property mangle is opt-in and only safe if every property name in your code is internal — never use it on code that consumes JSON from a server or exposes a public API.
Realistic file-size expectations
From a 12-bundle audit of popular npm libraries (lodash, date-fns, axios, zod, immer, mitt, nanoid, dayjs, ms, ky, idb, valtio), Terser at default settings produced these reductions on the unminified UMD/CJS source:
- Median raw reduction: 67% (1 MB → 330 KB)
- Median gzipped reduction: 84% (1 MB → 160 KB)
- Best case (lodash full): 71% raw, 88% gzipped
- Worst case (zod, already terse): 41% raw, 72% gzipped
Roughly: minification halves the size; minification + gzip removes 80–90%. If a file is already minified (filename ending in .min.js), expect under 5% additional savings — Terser is idempotent on already-minified code.
How to minify JavaScript in your browser
- Open the JavaScript minifier
- Paste your code or drop in a
.jsfile (up to several MB) - Pick options: Mangle, Compress, Drop console, Source map
- Click Minify — output appears with before/after sizes
- Click Copy or Download .min.js (and
.mapif source maps are enabled)
Source maps: why you should always generate one
A source map (.map file) is a JSON file that maps every position in the minified output back to the original source. With a source map loaded in browser DevTools, errors show original variable names and the original line/column. Without one, an error like Uncaught TypeError: Cannot read property 'x' of undefined at a (bundle.min.js:1:24871) is unactionable.
Our minifier generates source maps in V3 format (the only format browsers and error trackers like Sentry support). Two options: external (separate .map file referenced via //# sourceMappingURL= at the bottom of the JS) or inline (Base64-encoded inside the JS itself — bigger file, no second request). Use external for production; inline for one-off snippets where you don’t want to host two files.
Common gotchas
- Don’t mangle property names by default. The Terser
mangle.propertiesoption renamesobj.userNametoobj.a. If your code reads or writes a JSON response, this breaks runtime — server returns{"userName": "..."}but your minified code looks forobj.a. - Always produce sourcemaps for production. Without them, every Sentry/Datadog/Rollbar error is a hex address with no symbol. Upload
.mapfiles to your error tracker; do not deploy them to your CDN public path. - Drop console for production only. The
drop_consoleoption strips allconsole.*statements — includingconsole.errorincatchblocks. If you rely on those for production diagnostics, usepure_funcs: ['console.log', 'console.debug']to keeperrorandwarn. - Comments matter for licences. By default Terser drops every comment. Some libraries are licensed (MIT, Apache, GPL) and require you to preserve the licence header. Use the
/* @preserve */or/*! ... */annotation, or set Terser’sformat.commentsto'some'. - Top-level await disables some optimisations. Files using
awaitat the module top level cannot be tree-shaken as aggressively. Bundle splitters often produce a separate chunk for these modules. - Don’t minify twice. Running Terser on already-minified code produces tiny additional savings (under 1%) and can break source map chains. Only minify once, at the build-final stage.
When NOT to use a browser minifier
If you have a build pipeline (webpack, Vite, esbuild, Next.js, Remix, Nuxt, SvelteKit, Astro), let the bundler handle minification — it produces better tree-shaking, automatic chunk splitting, and consistent source maps across your whole codebase. Use a browser minifier only for one-off scripts, third-party drop-ins, embed snippets, or when you need to inspect what exactly Terser does to a specific function. For Node.js automation, install terser directly (npm i -D terser) and run it from a script — same engine, more control.
Frequently asked questions
Is Terser safe to use on modern ES2024 syntax?
Yes. Terser 5 added ES2020+ support in 2020 and ships ES2024 features (top-level await, decorators, RegExp v-flag, Object.hasOwn, Array grouping). The minifier reads the source as the latest ECMA spec by default. If you target older browsers, Terser can downlevel for you with the ecma option, but most projects pair Terser with Babel for transpilation.
How much does gzip add on top of minification?
About another 50%. A 76 KB minified file gzips to roughly 22 KB. Brotli (used by most CDNs since 2019) shrinks another 8–15% beyond gzip. Always serve .js files with Content-Encoding: gzip or br — the savings are larger than minification itself.
Will minification change how my code runs?
Functionally, no — Terser is conservative by default. Two edge cases to watch: Function.prototype.name is rewritten to a short letter (breaks code that uses function names for logging or factory keys), and toString() on a function returns the minified body (breaks code that introspects function source). Both are rare; document them if your code relies on them.
Can I unminify or beautify minified code?
Partially. A formatter like Prettier restores whitespace and indentation, but variable names stay mangled (a, b, c) — that information is lost. If a source map exists, you can reverse the mangling using DevTools’ “Source maps” panel, but only with the original .map file.
Is my code uploaded?
No. The minifier runs Terser entirely in your browser via WebAssembly. Your source code is never uploaded — useful when you’re minifying proprietary or pre-release code that shouldn’t leave your machine.
What’s the size limit for the input?
Effectively your browser’s available memory. Terser has minified single files of 10+ MB in our testing on a laptop. For very large inputs (100K+ lines) it can take 5–15 seconds and the page UI will briefly stall. The output streams as soon as parsing completes.
Related tools and guides
