About the JavaScript Minifier
Paste a script into this JavaScript minifier and Terser rewrites it as the shortest code that still does the same thing: comments and whitespace go, local variables get one-letter names, and branches that can never run are dropped. Terser parses your code the way a JavaScript engine does, so strings, template literals, regex literals and URLs containing // come through untouched.
Format mode goes the other way and runs Prettier over minified code, so a production bundle or a third-party snippet becomes readable again. Both libraries load the first time you use them and then run in your browser, so your code isn't sent anywhere.
- Paste your code into Input JavaScript, or click Load Example for a short script with comments and three kinds of strings.
- Minify is selected from the start. Leave Mangle and Compress ticked for the smallest output, and tick Keep Comments if a license header has to stay.
- Choose Single Quotes or Double Quotes. The choice applies to strings in both Minify and Format output.
- Read the output in Minified JavaScript. The three boxes above it, Original Size, Minified Size and Savings, update each time you pause typing.
- If Terser can't parse the code, JavaScript Error gives the position, for example
Line 5, column 1: Unexpected token: punc (})for a stray brace, and that line number turns red. TypeScript and JSX get an extra hint to compile them first. - Switch to Format to re-indent code in Formatted JavaScript. Copy and Download (
minified.jsorformatted.js) are in the top corner of the output box.
Input// Format a price for the shop's locale, e.g. 1234.5 -> "1.234,50 €"
function formatPrice(amount, locale, currency) {
const formatter = new Intl.NumberFormat(locale, {
style: "currency",
currency: currency,
});
return formatter.format(amount);
}
console.log(formatPrice(1234.5, "de-DE", "EUR"));Outputfunction formatPrice(r,e,c){return new Intl.NumberFormat(e,{style:'currency',currency:c}).format(r)}console.log(formatPrice(1234.5,'de-DE','EUR'));
312 B → 147 B, 52.9% savedThe parameters get one-letter names and formatter, used once, is inlined. formatPrice keeps its name because other scripts might call it. Both versions print 1.234,50 €.
InputThe formatPrice code above (312 B), with Single QuotesOutputMangle only (157 B):
function formatPrice(r,e,c){const n=new Intl.NumberFormat(e,{style:'currency',currency:c});return n.format(r)}console.log(formatPrice(1234.5,'de-DE','EUR'));
Compress only (181 B):
function formatPrice(amount,locale,currency){return new Intl.NumberFormat(locale,{style:'currency',currency:currency}).format(amount)}console.log(formatPrice(1234.5,'de-DE','EUR'));
Both off (207 B):
function formatPrice(amount,locale,currency){const formatter=new Intl.NumberFormat(locale,{style:'currency',currency:currency});return formatter.format(amount)}console.log(formatPrice(1234.5,'de-DE','EUR'));Dropping comments and whitespace alone saves a third. Renaming does most of the rest.
Input// A naive "remove everything after //" minifier breaks this file.
const API_URL = "https://api.example.com/v1/orders";
const COMMENT_LINE = /\/\/.*$/gm;
const banner = `Build: ${new Date(0).toISOString()}
two spaces kept`;
function stripComments(source) {
return source.replace(COMMENT_LINE, "");
}
console.log(API_URL, stripComments("a = 1; // note"), banner);Outputconst API_URL='https://api.example.com/v1/orders',COMMENT_LINE=/\/\/.*$/gm,banner=`Build: ${new Date(0).toISOString()}\n two spaces kept`;function stripComments(e){return e.replace(COMMENT_LINE,'')}console.log(API_URL,stripComments('a = 1; // note'),banner);The // in the URL, the regex and the string all survive. The template literal keeps its spaces, and its line break becomes \n, which is the same string.
Inputfunction formatPrice(r,e,c){return new Intl.NumberFormat(e,{style:'currency',currency:c}).format(r)}console.log(formatPrice(1234.5,'de-DE','EUR'));Outputfunction formatPrice(r, e, c) {
return new Intl.NumberFormat(e, { style: 'currency', currency: c }).format(r);
}
console.log(formatPrice(1234.5, 'de-DE', 'EUR'));Line breaks and indentation come back. The original names and the comment don't.
What Mangle, Compress and Keep Comments do
The checkboxes switch parts of Terser on and off, and the quote menu sets its output style:
- Mangle renames local variables and parameters. Top-level names and object properties are left alone (
cfg.longPropertyNamestays), because code outside the file may use them. Inside a function that callseval, nothing is renamed. - Compress rewrites the code: it inlines variables used once, folds constants (
24 * 60 * 60becomes86400), removesif (DEBUG)blocks whenDEBUGisfalse, deletesdebuggerstatements and writesfalseas!1. It keepsconsole.logcalls and unused parameters, so a function'slengthstays the same. - Keep Comments keeps every comment,
//lines too. With it off, even/*! ... */license headers are removed, so turn it on, or paste the header back, when a license requires it. - Single Quotes and Double Quotes pick the quote character, escaping it where needed:
"It's done"becomes'It\'s done'.
When minified code behaves differently
Terser parses your code into a syntax tree and prints it back in the shortest form, which is why code without semicolons comes out with them in the right places. Behavior only changes in these cases:
- Code that reads names. Inside a function,
handleClick.namereturned""after minifying, because Compress made the function anonymous; with only Mangle on it returned"n". Classes loseconstructor.namethe same way. Turn both options off for such code, or use Terser's--keep-fnamesand--keep-classnamesin your build. - A missing semicolon before a line starting with
[or(.const items = getItems()followed by[1, 2].forEach(...)was always one statement; the outputconst items=getItems()[2].forEach(...)just makes the bug visible. returnon its own line returnsundefined, so Terser drops the value on the next line as dead code andfunction total() { return\n 1 + 2; }becomesfunction total(){}.- Code inside strings, such as the argument of
evalornew Function, isn't minified.
Is it worth it if the server uses gzip or Brotli?
Yes. Compression squeezes repeated text but can't delete a comment or shorten a name, so the savings stack. We minified the unminified build of js-yaml 4.3.2 here with the default options and compressed both files with Node.js zlib (gzip level 6, Brotli quality 11):
- Raw: 131,632 bytes before, 43,560 after. 67% smaller.
- gzip: 22,440 bytes before, 14,282 after. Still 36% smaller.
- Brotli: 18,625 bytes before, 12,788 after. Still 31% smaller.
Minify JavaScript in your build
Use this page for one-off jobs: a snippet for a CMS or tag manager, a bookmarklet that must fit on one line, or checking what Terser does to a tricky function. In a project, minify in the build step so it happens on every change and writes a source map, which lets the browser's developer tools show your original file and line in stack traces. This page doesn't make source maps.
The commands below write app.min.js with a source map next to it; most bundlers do the same in production mode. For your other files, use the CSS Minifier and the HTML Minifier.
npx terser app.js --compress --mangle --source-map "url='app.min.js.map'" -o app.min.js
# Also remove console.* calls
npx terser app.js -c drop_console=true -m --source-map "url='app.min.js.map'" -o app.min.jsnpx esbuild app.js --minify --sourcemap --outfile=app.min.jsnpx prettier . --writeDoes minified JavaScript run differently?
No, it does the same work. The exceptions are code that reads function or class names, code that already has a semicolon bug, and code hidden in strings for eval, all listed in the Guide tab.
What is the difference between minifying and obfuscating?
Minifying makes code smaller, and Format makes it readable again in a second. Obfuscators encode strings and scramble control flow, which usually makes the file bigger and slower. Neither protects a secret: an API key in browser JavaScript is public either way.
Does the minifier remove console.log?
No, Compress keeps console calls because they're real code with visible output. To strip them in a build, run Terser with -c drop_console=true.
Why are some names not shortened?
Object properties are never renamed, and neither are top-level names or anything in a function that uses eval, because other code might refer to them. Wrap your code in a function to get top-level names shortened here, or use Terser's --module flag in a build.
Can I minify TypeScript or JSX?
Not directly. interface User {} stops with Unexpected TypeScript "interface" declaration and JSX with Unexpected token: operator (<). Compile with tsc or esbuild first, then minify. Format accepts JSX but not TypeScript.
Can minified JavaScript be reversed?
Partly. Format restores line breaks and indentation, but comments and original local names are gone. If a site publishes source maps, the browser's developer tools can show the original source.
How do I minify JSON?
Use the Minify button in the JSON Formatter. Terser reads {"a": 1} as a block of code and stops with Unexpected token: punc (:).