JavaScript Minifier

Compress JavaScript with Terser, the minifier most bundlers use. Local variables get short names and dead branches are dropped; the example below goes from 356 to 218 bytes. Terser loads from a CDN the first time you click Minify, and your code never leaves the tab.

JavaScript Input
Minified Output

1 JavaScript Minifier example

Source (356 bytes)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Debounce a function call
function debounce(fn, wait) {
    let timeout;
    return function (...args) {
        clearTimeout(timeout);
        timeout = setTimeout(() => fn.apply(this, args), wait);
    };
}

const onResize = debounce(() => {
    console.log("resized", window.innerWidth);
}, 200);

window.addEventListener("resize", onResize);

Minified (218 bytes)

1
function debounce(n,t){let e;return function(...o){clearTimeout(e),e=setTimeout(()=>n.apply(this,o),t)}}const onResize=debounce(()=>{console.log("resized",window.innerWidth)},200);window.addEventListener("resize",onResize);

2 What Terser does to your code

Renames locals

Variables and parameters inside a function get one-letter names. Most of the saving comes from this, and it is also why the output is hard to read. Untick Rename locals to skip it.

Drops dead code

An if (false) branch, a statement after a return, a variable that is assigned and never read: Terser removes all of them.

Rewrites for size

Terser joins statements with commas, turns if/else into a ternary where that is shorter, and writes true as !0. The behavior stays the same.

Keeps your exports

Top-level names are not renamed, and neither are exports or properties on window, so other scripts and inline handlers still find them.

3 When to use a build tool instead

Use a build tool for anything bigger than one file. This page suits a snippet for a CMS, a tracking widget or a small embed you paste into someone else's page. In a project, run Terser in your bundler: you get source maps, so a production stack trace points at a real line, and results are cached between builds. This page also strips every comment, /*! license */ blocks included, so add a required header back by hand.

Minifying is not obfuscation. The logic is all still there, and any pretty-printer turns it back into readable code in a second. Do not put a secret in client-side code and expect the minifier to hide it.

How to use the JavaScript Minifier tool

  1. Paste your JavaScript on the left, or load a file with Upload JS.
  2. Leave Rename locals ticked for the smallest output. Untick it for compressed code that keeps its variable names.
  3. Click Minify. Terser loads from a CDN on the first click, so the first run takes a moment longer.
  4. The header shows the size before and after. A parse error appears in red with Terser's description of the problem.
  5. Click Copy Result, or Download to save the output as script.min.js.

How to minify JavaScript with Terser, esbuild and a bundler

Command line

# Terser directly
npm i -D terser
npx terser src/app.js -c -m -o dist/app.min.js

# With a source map, so production stack traces still mean something
npx terser src/app.js -c -m --source-map "url='app.min.js.map'" -o dist/app.min.js

# esbuild is much faster and nearly as small
npx esbuild src/app.js --minify --sourcemap --outfile=dist/app.min.js

# Check the real cost, which is the compressed size
gzip -c dist/app.min.js | wc -c

Node.js API

const { minify } = require("terser");
const fs = require("node:fs");

const code = fs.readFileSync("src/app.js", "utf8");

const result = await minify(code, {
    compress: { drop_console: true, passes: 2 },
    mangle: { toplevel: false },   // keep top-level names for other scripts
    format: { comments: /^!/ },    // keep /*! licence */ comments
    sourceMap: { filename: "app.min.js", url: "app.min.js.map" },
});

fs.writeFileSync("dist/app.min.js", result.code);
fs.writeFileSync("dist/app.min.js.map", result.map);

drop_console removes every console call. Use it for production builds, and expect to miss those logs when you debug one.

Vite / Rollup config

// vite.config.js
export default {
    build: {
        minify: "terser",        // "esbuild" is the default and faster
        sourcemap: true,
        terserOptions: {
            compress: { drop_console: true },
        },
    },
};

// Most projects should stop here. A bundler minifies, splits chunks,
// tree-shakes and writes source maps in one pass, and caches the result.

Common errors and how to fix them

SyntaxError while parsing
Terser reads JavaScript, not TypeScript or JSX, so compile those first. It also treats input as a script unless told otherwise, so top-level await needs the module option.
The minified code breaks at runtime but the source works
This is usually name mangling meeting code that depends on names: a function referenced by string, a class name used in a lookup, a property read with bracket notation from a config. Keep those names with the reserved option, or stop relying on them.
A stack trace from production is unreadable
Generate source maps and upload them to your error tracker. Without them, minified traces point at line 1, column 40000.
Minified output is bigger than expected
Check whether the input was already minified. Running a minifier twice adds nothing, and a bundled file is mostly dependency code that arrived compressed.
A secret was found in the minified bundle
Minifying is not obfuscation. Anything in client-side code is public, and a pretty-printer undoes the formatting in one click. Move the secret server-side.

Good to know

Measure the gzipped size, not the minified size on disk. Minifying and gzip work on different things: the minifier removes characters, and gzip removes repetition. Say a 100 KB file minifies to 60 KB and then gzips to 18 KB, while the unminified file gzips to 22 KB. Measure both before deciding a build step is worth the complexity.

Specifications and references

This tool follows the specifications below. Read them when you need the exact normative wording, for example to settle an edge case between two implementations.

Frequently Asked Questions

What does the minifier use?

Terser, the compressor most build tools use. It loads from a CDN the first time you click Minify, so the page stays light for anyone who does not need it.

Does it rename my variables?

Local ones, yes, which is where most of the saving comes from. Top-level names, exports and properties on window keep their names, so external callers still work. Untick Rename locals to keep every name.

Which syntax is supported?

Modern JavaScript: classes, optional chaining, nullish coalescing, private fields. It compresses without transpiling, so the output targets the same engines the input did. TypeScript and JSX need compiling first, and the input is read as a script, so top-level await fails to parse.

Can I minify a whole bundle?

For a file or two, yes. For a real project, run Terser in your build so you get source maps and caching. This page is for the quick case: a snippet, an embed, a widget you are pasting into a CMS.

Is my code uploaded?

No. Terser is plain JavaScript and runs inside your tab. The library itself comes from a CDN, but your code never leaves the browser.

Related

Stylesheets go through the CSS minifier, and data through the JSON minifier. To read minified code again, the JSON formatter handles data and your browser's devtools have a pretty-print button for scripts.

More Code Formatters & Beautifiers

Browse all code formatters & beautifiers

Copied to clipboard!