
JavaScript Minifier & Beautifier
Paste your JavaScript to minify or beautify it instantly. 100% client-side - your code never leaves your browser.
Last reviewed: April 2026New to this tool? Click here for instructions
How to Use the JavaScript Minifier
To use the JavaScript Minifier, simply paste your JavaScript code into the input area on the left (or top on mobile). Choose a mode - Minify (default) compresses your JS, Beautify formats it with indentation. View the result instantly - the output panel updates as you type. Copy or download - copy to clipboard or save as output.js.
When to Use the Tool in Real Workflows
Use the JavaScript Minifier when you need to reduce the file size of your JavaScript code to improve load times. It's particularly useful for production builds where performance optimization is critical.
How It Works
The JavaScript Minifier uses a carefully designed parser to compress your JavaScript without breaking it. It handles the core challenge of JS minification: distinguishing comment-like sequences that appear inside strings and regular expressions from actual comments. The result is a compact, functional script ready for production use.
Tips, Edge Cases, or Limitations
For production builds, consider using your framework's built-in build process (Vite, webpack, or Rollup with the appropriate plugins) for advanced optimizations like variable name shortening, dead code elimination, and module bundling.
Frequently Asked Questions
Minify JavaScript for production or beautify minified code for debugging โ 100% in your browser, no upload required.
What This Tool Does
This tool handles both directions of JavaScript transformation: compressing source code for deployment and expanding compressed code back into readable form for inspection.
Minify Mode
Minify mode performs safe minification: it strips block and inline comments and collapses the whitespace that ECMAScript treats as non-significant, while leaving your identifiers and program structure intact. It does not rename (mangle) variables, fold constants, or eliminate dead code โ so the output is semantically identical to your input and safe for virtually any JavaScript. String, template, and regular-expression literals are preserved exactly, and statement boundaries on comment-free lines are kept as newlines so automatic semicolon insertion (ASI) never breaks semicolon-free code. After each run, the status bar reports the original byte count, the output byte count, and the percentage change. For aggressive production builds that also mangle names and run an Abstract Syntax Tree (AST) through dead-code and constant-folding passes, use a build-time tool such as Terser or esbuild (see the sections below for how those work).
Beautify Mode
Beautify mode takes compressed or poorly formatted JavaScript and re-indents it with consistent spacing, adds newlines at statement boundaries, and restores bracket alignment. Paste a minified npm package or vendor bundle and get back something a human can scan.
Privacy Note
๐ This tool runs 100% in your browser. Your source code is never uploaded, stored, or logged anywhere outside your local session.
How to Use It
Step-by-Step Instructions
- Paste JavaScript into the left input pane (or click Try Example to load a sample snippet).
- Pick a mode: Minify, Beautify (2 spaces), or Beautify (4 spaces).
- The output updates automatically as you type or switch modes โ there is no separate Run step.
- Check the status bar for the original size, the output size, and the percentage change.
- Click Copy to copy the result to the clipboard, or Download to save it as
output.js. Use Clear to empty the input.
Try the Example Button
Click Try Example to load a short sample โ two documented utility functions (formatBytes and debounce) with JSDoc comments. Switch to Minify to see the comments and indentation removed; switch to a Beautify mode to re-expand minified code.
Worked Example
The worked example below runs that built-in sample through Minify mode so you can see exactly what this tool removes and what it keeps.
Worked Example
- Input
- Built-in sample: two documented utility functions (
formatBytes,debounce), 876 bytes - Notable source contents
- Two JSDoc block comments, two line comments, indentation, blank lines, string and array literals
- Mode
- Minify
- Result
- 374 bytes โ a 57% reduction (before any gzip or Brotli)
Step-by-Step
- Click Try Example to load the sample into the input pane.
- Make sure the Minify chip is selected.
- Read the status bar: 876 B โ 374 B (-57%).
- Click Copy or Download to save the result as
output.js. - To sanity-check, switch to a Beautify mode and paste the minified code back in โ the structure and identifiers are unchanged.
Output
// Before (excerpt)
/**
* Formats a byte count into a human-readable string.
* @param {number} bytes - The number of bytes.
* @returns {string} Formatted string like "1.2 KB"
*/
function formatBytes(bytes) {
if (bytes === 0) return '0 B';
var units = ['B', 'KB', 'MB', 'GB'];
var i = Math.floor(Math.log(bytes) / Math.log(1024));
var value = (bytes / Math.pow(1024, i)).toFixed(1);
return value + ' ' + units[i];
}
// After (Minify)
function formatBytes(bytes){if(bytes===0)return'0 B';var units=['B','KB','MB','GB'];var i=Math.floor(Math.log(bytes)/Math.log(1024));var value=(bytes/Math.pow(1024,i)).toFixed(1);return value+' '+units[i];}
Result: 374 bytes โ 57% smaller. Both JSDoc blocks and the line comments are stripped and the indentation and blank lines are collapsed, while the 'B'/'KB' string literals and the formatBytes and debounce identifiers are preserved exactly. Nothing is renamed โ the output runs identically to the input, just without the spacing. (Pairing this with server-side gzip or Brotli pushes the bytes-transferred savings considerably higher.)
| Strategy | Original Size (KB) | Minified Size (KB) | Reduction (%) |
|---|---|---|---|
| Basic (whitespace only) | 18.4 | 12.1 | 34% |
| Standard (whitespace + comments) | 18.4 | 9.3 | 49% |
| Aggressive (whitespace + comments + mangle) | 18.4 | 6.1 | 67% |
| Pass / Option | What It Removes or Transforms | Typical Size Saving | Risk of Breaking Code | Recommended Default |
|---|---|---|---|---|
| Strip block comments | Removes /* โฆ */ blocks (except /*! โฆ */ license headers) |
5โ15% | Very low | โ On |
| Strip inline comments | Removes // โฆ line comments |
2โ8% | Very low | โ On |
| Collapse whitespace | Removes spaces, tabs, newlines not required by the grammar | 10โ20% | Very low | โ On |
| Mangle local variable names | Renames local variables to single characters (a, b, cโฆ) |
10โ25% | Medium โ breaks eval() and with |
โ On (disable if using eval()) |
| Mangle function names | Renames non-exported function identifiers | 3โ8% | Medium โ breaks stack-trace matching | โ Off |
| Constant folding | Replaces 2 * 60 * 1000 with 120000 at compile time |
1โ3% | Low | โ On |
| Dead-code elimination | Removes unreachable branches (if(false){โฆ}) |
1โ5% | Low | โ On |
| Inline single-use functions | Replaces a function called once with its body inline | 2โ6% | High โ can break React lifecycle and tagged template literals | โ Off |
Minification vs. Obfuscation: What's the Difference
What Minification Does
Minification targets file size and transfer speed. It removes characters the JavaScript engine never needed โ whitespace, comments, unnecessarily long identifiers โ and produces output that is semantically identical to the original. A developer who wants to read the result can paste it into the JavaScript Beautifier and have something legible within seconds. The logic is not hidden; the identifiers are shorter, not scrambled.
What Obfuscation Does
Obfuscation deliberately makes code hard to reverse-engineer. An obfuscator renames every identifier to a meaningless hexadecimal string, encodes string literals as Unicode escape sequences, adds synthetic dead-code branches to confuse static analysis, and sometimes applies control-flow flattening to turn readable switch statements into opaque dispatch tables. The output is still valid JavaScript, but recovering intent from it takes significant effort.
When to Use Each
Use minification for every production deployment โ it's a baseline performance optimization recommended by the W3C Web Performance Working Group. Obfuscation is warranted only when you have a specific deterrence requirement, such as protecting a proprietary algorithm shipped in a browser extension or a licensed SDK. The JavaScript Obfuscator on this site handles that use case.
Security Implications
Neither technique provides real security for sensitive logic. Per MDN's guide on client-side security, any secret โ API keys, cryptographic material, pricing logic you want to keep proprietary โ must not exist in browser-executed JavaScript. Obfuscation is deterrence, not encryption; a patient attacker with a debugger will get through it. If the logic genuinely must be secret, move it server-side.
Edge Cases and Gotchas
eval() and Dynamic Code
Variable mangling assumes every identifier used outside a string is renamed consistently at the AST level. That assumption breaks the moment your code calls eval() with a string that references a local variable by name โ the mangler renames the variable in the outer scope but leaves the string literal untouched, so the eval() call references a name that no longer exists. The same problem applies to with statements, which Terser documents explicitly. This in-browser tool never mangles, so it is safe for code that uses eval() or with; if you run a build-time minifier that does mangle, disable that option for such code.
Regex Literals vs. Division Operators
Naive regex-based tokenizers (not Terser, but older tools) misread the / inside a regex literal as a division operator, corrupting the token stream. If you're using a tool other than an AST-based minifier and you get a syntax error after minification, this is the likely cause. Terser's lexer handles this correctly by tracking parser state to distinguish the two contexts, per the ECMAScript 2023 grammar (ECMA-262 ยง12.8.5).
Template Literals
Tagged template literals โ the kind used by styled-components (css`color: red`) and GraphQL clients (gql`query { โฆ }`) โ must not be inlined. The tag function receives the raw string array as its first argument; inlining the call site eliminates that boundary and produces incorrect output. This tool does not inline functions, so it leaves tagged templates intact; in a build-time tool, keep the function-inlining pass off for any codebase that uses tagged templates.
Source Maps
Without a source map, a production exception lands on line 1, column 4,217 of a single concatenated file โ useless for debugging. Always generate a .map file alongside your minified output for any deployment where you intend to diagnose errors. Webpack, Vite, and esbuild all support sourcemap: true or equivalent flags. Store the source map on your error-tracking server (Sentry, Rollbar) rather than serving it publicly if you want to keep the original source private.
ES Module Syntax and Parser Targets
ES2020+ features โ optional chaining (?.), nullish coalescing (??), logical assignment (||=) โ require the minifier's parser to be configured for at least ES2020. If you're targeting older browsers and transpiling with Babel first, minify the transpiled output, not the original source. Minifying ES2020 syntax and then running Babel on the result can produce invalid code.
Double-Minifying
Minifying already-minified code rarely yields additional savings and occasionally corrupts string literals if the first pass produced non-standard whitespace sequences inside template literals. Run the minifier once on human-readable source, not on previously processed output.
How JavaScript Minification Works Under the Hood
Lexing and Tokenization
The first pass converts raw source text into a flat token stream. Each token is a classified unit: an identifier (calculateDiscountedPrice), a numeric literal (0.15), a punctuator ({), or a string literal ('discountRate must be between 0 and 1'). Whitespace and comment tokens are classified as non-significant per ECMAScript 2023 ยง12.2 and discarded at this stage.
AST Parsing
The token stream is parsed into an Abstract Syntax Tree following the ECMAScript 2023 grammar (ECMA-262). The AST represents the program's structure as a tree of nodes โ a FunctionDeclaration node contains Param nodes and a BlockStatement body โ rather than as raw text. This representation is what makes AST-based minifiers safe: every transformation operates on known node types rather than on character patterns that might appear in string literals or regex bodies.
Transformation Passes
Multiple passes walk the AST and apply reductions: dead-code elimination prunes branches whose conditions evaluate to a known constant; constant folding replaces expressions like 24 * 60 * 60 * 1000 with 86400000; inline expansion substitutes the body of a function called exactly once at its call site; and the mangling pass builds a scope-aware rename table that assigns the shortest available identifier to each local binding.
Code Generation
The transformed AST is serialized back to JavaScript source text, omitting every non-significant whitespace token. The result is syntactically valid, semantically equivalent code in the fewest possible bytes.
Terser's Compression Pipeline
Terser (github.com/terser/terser) is the de-facto standard for this pipeline. It powers webpack's TerserWebpackPlugin (included by default in mode: 'production'), Vite's built-in production build, and the Rollup ecosystem via @rollup/plugin-terser. esbuild implements a comparable pipeline in Go with faster execution. The W3C Web Performance Working Group cites minification as a baseline optimization in its Resource Hints specification.
Minification Strategies for Production Bundles
Bundler Integration (webpack, Vite, esbuild)
All three major bundlers handle minification automatically in production mode, with zero configuration required for most projects:
- webpack: Set
mode: 'production'inwebpack.config.js.TerserWebpackPluginruns by default with sensible defaults. To customize, pass aterserOptionsobject. - Vite: Run
vite build. Minification is on by default viabuild.minify: 'esbuild'(fast) or switch to'terser'for more aggressive compression at the cost of slower build times. - esbuild: Pass
--minifyto enable all three minification passes simultaneously (identifiers, whitespace, and syntax). For fine-grained control, use--minify-identifiers,--minify-whitespace, and--minify-syntaxindividually.
Tree Shaking vs. Minification
Tree shaking (dead-code elimination at the module graph level) and minification are complementary, not interchangeable. Tree shaking removes entire unused exports before the bundle is assembled; minification then compresses what remains. Always tree-shake first โ sending dead modules to the minifier wastes build time and produces a larger output than eliminating the modules beforehand.
Measuring Impact with Chrome DevTools Coverage Tab
Open Chrome DevTools, press Ctrl+Shift+P, type Coverage, and start recording. The Coverage tab reports how many bytes of each JavaScript file are actually executed during the current page load. Target less than 20% unused bytes on the critical path. The HTTP Archive 2023 Web Almanac puts the median JavaScript transfer size on mobile at 509 KB; minification alone cuts 30โ70% of that, and pairing it with Brotli or gzip compression at the server level typically pushes effective transfer savings above 80%.
| Bundler | Plugin / Flag | Config Key | Minifies by Default in Production? | Source Map Option |
|---|---|---|---|---|
| webpack | TerserWebpackPlugin |
mode: 'production' |
Yes | devtool: 'source-map' |
| Vite | esbuild / Terser (selectable) | build.minify: 'esbuild' |
Yes | build.sourcemap: true |
| esbuild | Built-in | --minify |
No (explicit flag required) | --sourcemap |
| Parcel | Built-in (SWC) | Automatic in production | Yes | --detailed-report / config |
| Rollup | @rollup/plugin-terser |
plugins: [terser()] |
No (plugin required) | output.sourcemap: true |