JavaScript Minifier
Shrink JavaScript with a real parser (Terser), not a fragile regex — comments and whitespace gone, locals compressed and mangled, while strings, template literals and regex literals stay byte-exact. Nothing is uploaded.
Runs entirely in your browser — your code never leaves your device. Minification uses the vendored Terser parser and a small script you can read; the byte figures are measured directly with TextEncoder.
What this tool does
Paste a script on the left (or open a .js file) and it is minified on the right the instant you stop typing — no button to hunt for. You get the smallest safe version of your JavaScript, its size before and after in real bytes, and the exact percentage saved. Then copy it or download it as script.min.js. Everything happens on your device: the minifier is a full JavaScript parser vendored into the page, so nothing is uploaded.
Why a parser, not a regex
The tempting way to minify JavaScript is a handful of regular expressions: delete // to the end of the line and /* … */ pairs, then squeeze runs of whitespace. It works on tidy input and quietly corrupts the awkward bits. A string such as "visit http://x // now" contains both a // that is not a comment and a colon-slash that a regex will misread. A regex literal like /a\/\/b/ looks, to a blind pattern matcher, like the start of a comment. A template literal `x ${y}` has its own nested expression grammar. This tool avoids all of that by running Terser, which lexes and builds an abstract syntax tree first — so a slash inside a string is never mistaken for a comment, and the only thing it can output is syntactically valid JavaScript.
Worked example
Feed it this (about 168 bytes):
// add two numbers
function add(first, second) {
/* nothing clever here */
return first + second;
}
console.log(add(2, 3));
and you get back (about 62 bytes, ~63% smaller):
function add(d,n){return d+n}console.log(add(2,3));
Note what changed and what did not: both comments and every scrap of layout whitespace are gone, and the local parameters first/second were mangled to one-letter names — but add kept its name because it is top-level (Terser does not mangle top-level names by default, so anything you export stays callable). A string literal or regex in that code would have survived byte-for-byte.
What it removes and what it keeps
| Removed / shortened | Always preserved |
|---|---|
Comments (// and /* … */) | Text inside strings and template literals |
| Insignificant whitespace & newlines | Regex literals, exactly as written |
| Local variable names (mangled short) | Top-level & exported names (by default) |
| Dead code & provably constant expressions | Program behaviour and evaluation order |
| Redundant semicolons & blocks | The language level (no transpiling) |
How the byte savings are measured
The “before” and “after” numbers are the true UTF-8 byte length of the input and output, read with the browser's TextEncoder — never the character count and never a guess. The percentage is simply (before − after) / before. Counting bytes rather than characters matters the moment your code contains anything multi-byte — an accented word in a comment, an emoji in a string, non-Latin identifiers — because those weigh more than one byte each and a character count would understate the real transfer size.
Honest limits
This is a single-file minifier, not a bundler. It shrinks one script's text: it does not follow import/require, resolve a module graph, or tree-shake across files — reach for a bundler if you need that. It parses standard JavaScript up to modern ES2020+ (classes, private #fields, async/await, optional chaining, nullish coalescing, template literals, BigInt), but it is not a TypeScript, JSX or Flow parser — strip those to plain JavaScript first or Terser will report a syntax error. It minifies; it never transpiles, so output runs wherever your input already ran, not on older engines. Because a syntax error cannot be safely guessed past, invalid input yields an inline error and no output rather than best-effort garbage. Mangling is limited to local names by default so your public API keeps working; if you rely on reading local variable names at runtime (some very old frameworks did), review the output. Very large files are minified synchronously and may briefly freeze the tab while Terser works.