JavaScript Minifier
Paste a source and read the minified file back beside it, with the byte count before and after and a plain list of what changed. This page is a scanner and a printer rather than a compiler: comments go, the whitespace between tokens goes, a line break that ended a statement becomes the semicolon it stood for, and a local name is shortened only when one function declares it and nothing outside that function uses it. Nothing else moves. No expression is folded, no branch is dropped, no brace is removed and no property name is touched, which is why the 208 byte sample on this page comes back as 88 bytes, 57.7% smaller, with totalPrice kept and 4 local names renamed rather than the last byte squeezed out of it. Every result is read back and compared with the source token by token before it reaches the pane, and a file the scanner cannot follow returns the line and column instead of a partial file.
- Mode
- Syntax newer than this is reported beside the result. Nothing is rewritten to reach it.
- Rename
- Source map
208 to 88 bytes, 57.7% smaller totalPrice kept, 4 local names renamed
- Input
- 208 B
- Output
- 88 B
- Saved
- 57.7%
- Mode
- Module, ES2020
- 208 to 88 bytes, 57.7% smaller
- totalPrice kept, 2 local names renamed
- Line 1, column 28: the { opened here is never closed. Nothing was minified: close it and run it again.
Up to 1,000,000 bytes in one pass, minified here in your browser with nothing uploaded, nothing executed and no account. Script mode refuses an import or export, because a script cannot run one; the ECMAScript setting reports syntax newer than the one you pick rather than rewriting it, because this page minifies and does not transpile. The mode, the target, the rename and source map settings and the draft are kept in this browser alone, drafts up to 200,000 characters, and the Start over button above the tool forgets them.
Common questions
- Can minifying change what my code does?
- That is the question the whole page is built around, and three rules answer it. First, every token is written back exactly as it was read: nothing is reordered, no string, template literal or regular expression is touched, and where two tokens would read back as a third a space stays between them. Second, a line break is only ever deleted when the parser would have read straight across it. JavaScript ends a statement at a line break in some places, so a minifier that simply joined your lines could quietly change the file. Here a break that ended a statement becomes the semicolon the parser was going to insert, and a break after return, break, continue or yield always does, because those end their statement whatever follows. Third, the result is read back: the output is scanned again and compared with the source token by token, allowing only a removed comment, an inserted semicolon and a semicolon dropped against a closing brace. If that comparison fails, the run is repeated with renaming switched off, and if it fails again you get a message rather than a file.
- Which names get renamed, and which are kept?
- A name is shortened only when every one of these holds: it is declared inside a function, every declaration of it in the file sits inside a function, those declarations do not nest inside one another, and every use of it falls inside one of them. Anything else keeps its name. That means a top level function, variable or class keeps its name, so does anything you export, and so does every property, method, getter, class member and shorthand property, because renaming one of those would rename part of your interface rather than part of your implementation. A name that appears anywhere inside a template literal is left alone too: the scanner reads a template as a single token, so it cannot see what a rename inside one would do. A file containing eval or with has nothing renamed at all. Each shortened name is picked from short names that appear nowhere in your file, so no rename can shadow or capture another name.
- Is my code uploaded, executed or logged anywhere?
- No. The minifier runs in your browser, which is the point when the file is a client bundle or something under an agreement. There is no account, no sign-up and no upload, the page makes no network request of its own, and nothing you paste is ever evaluated: the scanner reads characters and the printer writes them, so a source with a call to something dangerous in it is text, not a program. Your draft is remembered on this device alone, up to 200,000 characters of it, and the Start over button above the tool forgets the draft along with the mode, the target and the rename and source map settings.
- Why is the saving smaller than another minifier's?
- Because this page does less on purpose, and says which less. It does not fold constants, drop unreachable code, remove the braces around a single statement, turn an if into a conditional expression, rewrite a function into an arrow, hoist declarations together or reuse a short name in two scopes. Each of those needs a parser, a syntax tree and a set of assumptions about your program, and each is a place a minifier can change behaviour. What is left is the part that is safe to argue about token by token: comments, whitespace, redundant semicolons and private local names. On the sample here that is 57.7% of the file. A build step compressing a whole bundle will beat it, and should.
- What is the difference between Script and Module mode?
- It is the difference the engine itself makes. An import or export statement can only run inside a module, so in Script mode one is refused with the line and column it sits on and the suggestion to switch, rather than minified into a file that will not load. import.meta is refused the same way, while a dynamic import call is fine in both, because a script may call one. Nothing else about the output changes between the two: both keep every name that is reachable from outside the file.
- What does the ECMAScript setting do?
- It reports, it does not transpile. Pick ES5, ES2015, ES2020 or Latest, and anything newer than your pick is named beside the result with its line and column: an arrow function as ES2015, optional chaining as ES2020, a class static block as ES2022, and so on. The output is still produced, because this page never rewrites syntax and could not lower a template literal into string concatenation even if you asked. Use it as a check on a file you believe is already at a level, not as a compiler.
- Can I get a source map?
- Yes. Switch Source map on and the Map button saves a version 3 map beside the minified file. It carries one mapping for every token, the original source under sourcesContent so the map stands on its own, and the original spelling of every name that was shortened, so a debugger shows you subtotal where the file says n. The byte counts in the readout are of the code alone; the map is a separate file and no sourceMappingURL comment is added to your output unless you add one.
- Does it handle TypeScript, JSX or a framework file?
- No, and it says so instead of guessing. A type annotation on a variable, a parameter, a return type or a class member, an interface, an enum, a type alias, a declare, a namespace, an implements clause, a non-null assertion, an optional parameter marker, an as assertion or a member modifier such as private, readonly or abstract stops the run with the line and column it was found on and the advice to compile first. So does JSX, whose angle brackets a JavaScript scanner cannot read. Paste what your compiler produced and it minifies like any other source. A whole HTML page is refused too, with a note to paste the contents of the script element on its own.
- How much can I paste, and what happens to a file that is too large?
- Up to 1,000,000 bytes in one pass, which is a large bundle. Past that the page tells you how large your paste is and how large it may be, and minifies nothing until you split it. It never truncates: a minifier that silently dropped the end of your file would be worse than one that refused it. A run that somehow takes longer than the time the page allows returns the same kind of message, with no partial file behind it.
Minified in your browser by a scanner and printer written for this page: your code is read as tokens and written back, never run and never uploaded, and the byte counts are of the exact text in each pane, counted as UTF-8. Comments go apart from a licence header, the whitespace between tokens goes, a line break that ended a statement becomes a semicolon, and nothing else moves: no syntax is rewritten, no brace is removed and no property name is touched. Renaming is limited to names declared inside a function and used nowhere else, so anything reachable from outside the file keeps its name. Every result is read back and compared with the source token by token before it is shown, and a parse it cannot follow returns the line and column instead of a partial file.