In short: what does a JavaScript minifier do?
A JavaScript minifier strips the characters an engine does not need to run your code — comments, indentation, blank lines and redundant whitespace — and can optionally drop console and debugger statements to produce a smaller, faster-parsing script that behaves identically. This tool performs safe, lossless, ASI-aware minification, lets you beautify minified code, run a deep analyzer with cyclomatic complexity, score quality, security and performance, audit for XSS and risky patterns, detect your framework, surface memory and Core Web Vitals issues, convert between CommonJS and ES modules and even run code in a sandbox — all 100% in your browser, with nothing ever uploaded.
Safe, lossless minification
Strip comments, blank lines and whitespace with ASI-aware, conservative-by-default options.
Beautify & format
Pretty-print minified or machine-generated JavaScript with your chosen indentation.
Analyzer with complexity
Functions, variables, imports/exports, loops, cyclomatic complexity and nesting depth.
Security audit
Flags eval, XSS DOM sinks, hardcoded secrets and risky patterns with line numbers and fixes.
Framework detection
Recognises React, Next.js, Vue, Angular, Svelte and more with tailored optimization tips.
Live execution sandbox
Run code in an isolated iframe to see console output, errors and execution time safely.
What is JavaScript minification?
JavaScript is the language that drives behaviour on the web — the functions, classes, modules and event handlers a browser downloads, parses, compiles and executes to make a page interactive. To stay readable while you author it, JavaScript is normally written with generous indentation, blank lines between functions, explanatory comments and one statement per line. None of that formatting affects how the code runs: the engine tokenises the source, builds an abstract syntax tree and executes the result regardless of how the file was spaced. The whitespace and comments exist purely for the humans who write and maintain the code.
JavaScript minification is the process of removing exactly those redundant characters — comments, insignificant whitespace, blank lines and indentation — and optionally stripping development-only statements such as console.log and debugger, so the file becomes as small as possible while running identically. It is a lossless transformation in the only sense that matters: the behaviour, output and side-effects that reach the user are exactly the same, but the script arrives in far fewer bytes and the engine has less text to scan before it can start work. Where beautifying spreads code out for readability, minifying does the inverse, packing the script tight for delivery.
A good JavaScript minifier is also conservative, because JS has a uniquely subtle hazard: automatic semicolon insertion (ASI). The parser sometimes treats a line break as the end of a statement, so blindly deleting a newline can silently change what the code means — turning two statements into one, or breaking a return that relied on the line ending. This tool tokenises your source and only collapses a newline when the surrounding tokens prove it is safe — after an open brace, comma or operator, or before a closing bracket — so statement boundaries always survive. License banners (comments beginning /*! or containing @license or @preserve) are kept by default to honour legal notices.
Minification sits at the very end of the authoring pipeline: you write clean, well-formatted JavaScript for yourself and your team, and the minifier produces the compact version that ships to production. This tool tokenises your code once into a structured stream, then walks that stream applying each enabled optimisation — so you get the savings without the risk of a broken script. Because every step runs locally using browser APIs, you can safely paste proprietary modules, unreleased features and confidential logic; nothing leaves your device.
Why JavaScript optimization matters
JavaScript is the most expensive resource on most modern pages — not because of its transfer size alone, but because of what the browser must do after it arrives. Unlike an image, every byte of script has to be parsed, compiled and executed on the main thread before it can do anything, and that work competes directly with rendering and user input. A kilobyte of JavaScript costs far more than a kilobyte of an image, so trimming comments, indentation and dead statements does not just save bandwidth: it reduces the parse and compile cost that holds up interactivity. On slow mobile CPUs, where parse-and-compile time can dwarf download time, the difference is dramatic.
The benefits compound across four dimensions. Parse and compile cost: fewer bytes mean less source for the engine to tokenise and compile before execution can begin. Main-thread relief: a leaner script occupies the single UI thread for less time, so the page stays responsive to taps and clicks. Bandwidth: at scale, smaller files multiplied by millions of requests is a real reduction in data served, and a kindness to users on metered plans. Core Web Vitals: lighter JavaScript contributes to better LCP and lower Total Blocking Time, and keeping the main thread free helps INP stay responsive — all of which are ranking and user-experience signals. Most CDNs and hosts also bill by egress, so smaller responses lower the bill.
Crucially, none of this changes how your code behaves. The engine runs the same statements from minified JavaScript, so the result is identical — only the delivery and parsing are faster. Safe minification is one of the rare optimisations that is essentially free of downside when done conservatively. Here is what gets removed and how safe each transformation is:
| What gets removed | Effect | Safety |
|---|---|---|
| Comments | High — comments can be verbose | Safe (/*! license comments kept) |
| Whitespace | Highest — indentation dominates source | Safe — never inside strings/templates |
| Blank lines | Collapsed to a single newline | Safe — ASI boundaries preserved |
| console.* calls | Standalone statements removed (opt-in) | Safe — expression-value calls kept |
| debugger | Statement removed (on by default) | Safe — no effect in production |
| Redundant spaces | Joined unless tokens would merge | Safe — spaces kept where needed |
For typical hand-written or framework-authored modules — which carry plenty of indentation, comments and blank lines — savings of 20–50% on the raw source are common before gzip, and far more after Brotli or gzip compression. The tool shows the exact bytes saved and the percentage reduction for your specific input in real time, so you can see the win immediately and verify that the minified code still behaves the same in the sandbox.
JavaScript performance guide
Minification shrinks the bytes, but how your JavaScript behaves once it runs has an even larger effect on how a page feels. The single most important fact about browser JavaScript is that it runs on one main thread — the same thread that handles layout, painting and user input. Anything the script does for too long blocks all of that, which is why the discipline of front-end performance is largely the discipline of keeping the main thread free. The Performance and Web Vitals tabs in this tool surface the patterns that hold it hostage and return targeted, code-aware recommendations.
It helps to separate two distinct costs. Parsing and compiling happens once, when the script first loads, and scales with how many bytes you ship — which is exactly what minification, tree shaking and code splitting attack. Execution happens every time the code runs, and is dominated not by file size but by what the algorithms actually do. A tiny function with an accidental nested loop can be far more expensive than a large file that runs once. Optimising for performance means reducing both: ship less code, and make the code you do ship do less work on the main thread.
- Avoid long tasks. Any single piece of JavaScript that runs for more than 50ms is a “long task” that freezes the UI for its duration — the chief cause of poor INP. Break heavy work into smaller chunks, yield with
scheduler.yield()orrequestIdleCallback(), and defer non-critical work until the page is interactive. - Debounce and throttle. Events like
scroll,resizeandinputfire rapidly; running expensive handlers on every one floods the main thread. Debouncing waits until the storm settles before running once; throttling caps the rate to, say, one call per frame. Both keep handlers cheap and the page responsive. - Offload to Web Workers. A Web Worker runs JavaScript on a separate thread with no DOM access, communicating by messages. Move CPU-heavy work — parsing, crunching, image processing — into a worker so the main thread stays free to paint and respond. This is the most reliable way to keep a heavy app interactive.
- Avoid layout thrash. Reading a layout property (like
offsetHeight) after writing one forces the browser to recompute layout synchronously; doing it in a loop causes “layout thrashing” that destroys frame rates. Batch all reads, then all writes, and prefer compositor-friendlytransformandopacityfor animation. - Watch your algorithms. The analyzer flags obvious nested loops, which are often accidentally O(n²); replacing a linear scan inside a loop with a
MaporSetlookup turns quadratic work into linear and can be the single biggest execution-time win.
Treat the performance score as directional guidance rather than gospel — it is a fast static-analysis heuristic, not a full Lighthouse run or a CPU profile — but the checks point you straight at the highest-leverage fixes: synchronous network calls, logging inside loops, oversized files and main-thread-blocking patterns that are worth restructuring before you ever ship.
Bundle optimization techniques
For a real application, the most consequential performance decision is not how tightly you minify a single file but how much JavaScript you ship in the initial bundle. Every byte in that first download must be fetched, parsed and compiled before the page can become interactive, so the goal of bundle optimisation is simple: send the smallest amount of code needed to render and respond to the first view, and load everything else only when it is actually required. The analyzer and Web Vitals tabs surface where the biggest wins are hiding in your code.
Code splitting is the highest-leverage technique. Instead of bundling the entire application into one monolithic file, you break it into chunks that load on demand — typically one per route and one per heavy feature. The dynamic import expression — import('./chart') — returns a promise and tells the bundler to emit a separate chunk that is only fetched when that line executes. Frameworks build on this with helpers like React.lazyand Vue's async components, so a dashboard's charting library never weighs down the login screen.
- Lazy-load rarely-used features. Modals, editors, date pickers and admin panels that most users never open should not sit in the critical bundle. Load them on the interaction that needs them, so the first paint carries only what the first view requires.
- Audit your dependencies. A single heavy library can dwarf all your own code. Check the cost of each dependency, prefer lighter or native alternatives (the platform now ships
fetch,Intl,structuredCloneand date APIs), and import only the functions you use rather than an entire utility package. - Compress on the wire. Minify to remove literal redundancy, then serve the result with Brotli or gzip. The two attack different redundancies, and minified JavaScript compresses slightly better because there is less repetitive text to encode. Brotli typically beats gzip by a useful margin on text.
- Cache aggressively. Emit content-hashed filenames (
app.4f2a.js) and serve them with a longmax-ageandimmutable. Returning visitors then re-download only the chunks that actually changed, and the rest is served instantly from cache. - Preload what you will need soon. Use
<link rel="modulepreload">or route-level prefetching to warm the cache for the chunk a user is about to navigate to, so the split feels instant rather than introducing a visible delay.
The workflow ties together: split the bundle so the initial download is small, lazy-load the rest, tree-shake unused exports, then minify and compress what remains and cache it at the edge. This tool covers the per-file slice of that pipeline — safe minification, analysis and the signals that tell you where to split — while your bundler (esbuild, Rollup, webpack or Vite) automates the chunking. Used together, they turn a heavy monolith into a lean, fast-loading set of chunks.
Tree shaking explained
Tree shaking is dead-code elimination at the module level: a bundler statically analyses which exports are imported across your whole project and drops the ones nothing references, so unused library code never reaches the browser. The name is the metaphor — you shake the dependency tree and the dead leaves fall off. Done well, it can cut a large utility library down to the handful of functions you actually call, and it is one of the most effective ways to shrink a bundle without touching a line of your own logic.
The technique depends entirely on ES modules. Because import and export are static — the names are fixed at parse time and cannot be computed at runtime — a bundler can build a precise graph of what is used and what is not before the code ever runs. That static structure is what makes tree shaking possible. The bundler walks every import, marks the exports that are reachable, and discards the rest as dead code during the build.
CommonJS resists tree shaking for exactly the opposite reason. A CommonJS require() is a regular function call that can be conditional, dynamic or wrapped in logic, and module.exports can be reassigned at runtime — so a bundler cannot prove which parts of a module are unused without running it. The practical lesson is to author and publish libraries as ES modules (or ship both), and to import named exports (import { debounce } from 'lib') rather than a whole namespace, so the bundler has the static information it needs to prune aggressively.
| Factor | Tree-shakeable? | Why |
|---|---|---|
| ES modules (import/export) | Yes | Static bindings let the bundler trace usage |
| CommonJS (require) | Rarely | Dynamic calls cannot be statically proven unused |
| Named imports | Best | Bundler keeps only the exports referenced |
| Namespace import (* as x) | Limited | Whole namespace may be retained |
| sideEffects: false | Enables | Tells the bundler a package is pure to prune |
| Side-effectful modules | No | Code that runs on import must be kept |
The sideEffects field in package.json is the contract that unlocks the most aggressive pruning. Setting "sideEffects": false tells the bundler that importing any module from the package has no observable effect beyond its exports — no global registration, no polyfill installation — so any unused export can be dropped wholesale. If some files do have side-effects (a CSS import, a one-time setup), you list just those paths so the bundler keeps them while still shaking the rest. Getting this flag right is often the difference between a library that tree-shakes beautifully and one that drags its entire surface into every bundle.
Real tree shaking belongs to a bundler — esbuild, Rollup, webpack and Vite all do it during the build, where they have the whole module graph in view. A single-file tool cannot safely perform it, because knowing whether an export is unused requires seeing every other module that might import it. What this tool does instead is statically detect the signals it can see from one file: unused declarations, dead imports that are never referenced, and unreachable patterns. Those are exactly the candidates worth cleaning up before you hand the project to a bundler, and pairing the two — local analysis here, graph-wide elimination in the build — is how you ship the leanest code.
JavaScript security best practices
Because JavaScript runs in the user's browser with access to the page, cookies and storage, insecure code is not just a bug — it is an attack surface. The Security tab in this tool performs a static audit that flags risky patterns with line numbers and a severity, returning an overall security score so you can spot the obvious dangers in seconds. It is a heuristic to catch common mistakes quickly, not a replacement for a full SAST tool or a human review, but it points you straight at the patterns that cause real incidents.
The most dangerous primitive is dynamic code execution. eval() and the Functionconstructor turn a string into running code, so if any part of that string can be influenced by user input you have handed attackers a way to run arbitrary JavaScript in your users' sessions. The same applies to passing a string to setTimeout or setInterval, which evaluates it like eval. There is almost always a safer structured alternative — a lookup table, a parser, or simply passing a function instead of a string — and the audit flags every one of these as high severity.
The most common vulnerability is cross-site scripting (XSS), which happens when untrusted data is written into the DOM as markup. Assigning user-controlled content to innerHTML, outerHTML or via insertAdjacentHTML and document.write lets an attacker inject <script> tags or event handlers that run in your origin. The fix is to treat data as data: use textContent, which never parses HTML, for plain text, and when you genuinely must render HTML, sanitise it first with a vetted library like DOMPurify. In React, the same hazard wears the name dangerouslySetInnerHTML, and the warning is in the API for a reason.
| Risky pattern | Safer alternative |
|---|---|
| eval(str) / new Function(str) | Parse data; use a lookup map or structured logic |
| el.innerHTML = userInput | el.textContent = userInput, or sanitise with DOMPurify |
| setTimeout("code", t) | setTimeout(() => code, t) — pass a function |
| const key = "sk_live_..." | Read from env vars / a secrets manager at runtime |
| obj[userKey] on prototype | Validate keys; use Map or Object.create(null) |
| http://api.example.com | https:// to avoid mixed content and MITM |
Two quieter risks round out the audit. Hardcoded secrets — API keys, tokens and passwords baked into client code — are visible to anyone who opens DevTools, so credentials belong in environment variables or a secrets manager and should never be committed; the scanner flags string literals that look like secrets. Prototype pollution happens when attacker-controlled keys reach __proto__or are assigned dynamically onto an object's prototype, corrupting objects across the whole application; the defence is to validate keys and use a Map or Object.create(null) for untrusted dictionaries. Finally, insecure http:// URLs invite mixed-content and man-in-the-middle problems and should be upgraded to https://. Every one of these is surfaced with a line number and a recommended fix, so you can harden the code where it actually matters.
Modern JavaScript architecture
As a codebase grows, the hardest problem in JavaScript is not writing features but keeping the code predictable — avoiding the slow slide into tangled state, surprise mutations and functions that do ten things at once. A deliberate architecture keeps modules small, testable and easy to reason about, and the tool's Quality audit rewards exactly the habits that good architectures encourage: modern declarations, low complexity, shallow nesting and clean production code.
The foundation is the module system. ES modules (import/export) are the modern standard: static, statically analysable, tree-shakeable and supported natively in browsers and Node. CommonJS (require/module.exports) is the older Node format — dynamic, harder to optimise and resistant to tree shaking. New code should be authored as ES modules, and this tool's Convert tab can transform existing CommonJS into ESM (and back) to ease migrations, handling the common require-to-import and module.exports-to- export forms as a best-effort source transform.
Within a module, a handful of habits separate maintainable code from the fragile kind. Prefer const by default and let only when a binding must be reassigned; avoid var entirely, because its function-scoping and hoisting cause subtle bugs that block-scoped declarations simply do not have. Use strict equality (=== / !==) so comparisons never silently coerce types. Reach for async/await over nested callbacks or long promise chains, so asynchronous flows read top-to-bottom and errors propagate through ordinary try/catch. The Quality audit counts var usage and loose comparisons directly, so these habits show up in your score.
The deeper principles are immutability, pure functions and separation of concerns. Treating data as immutable — building new objects and arrays with spread and array methods rather than mutating in place — makes state changes explicit and predictable, which is exactly why frameworks like React lean on it. A pure function depends only on its arguments and produces no side-effects, so it is trivially testable and safe to reuse; pushing logic into pure functions and isolating the impure edges (DOM, network, storage) is the essence of separation of concerns. Keep functions small and single-purpose, flatten nesting with early returns and guard clauses, and the cyclomatic-complexity and nesting checks in the analyzer will reward you — because the same properties that make code score well are the ones that make it a pleasure to change.
Memory optimization guide
JavaScript is garbage-collected, so memory is reclaimed automatically once nothing references an object — but that is precisely the trap. A memory leak in JavaScript is not memory the engine forgot to free; it is memory your code is still referencing long after it is needed, so the collector cannot touch it. In a long-lived single-page application those references accumulate, the heap grows, and the tab eventually slows to a crawl or crashes. The tool's memory hints surface the patterns most likely to cause this, as directional signals to investigate.
Four sources cause the overwhelming majority of leaks. Event listeners attached with addEventListener but never removed keep their callback — and everything that callback closes over — alive for as long as the target element exists. Timers from setInterval (and pending setTimeout calls) hold their closures forever unless you clearInterval / clearTimeout them. Closures that capture large objects keep those objects reachable for the lifetime of the closure. And detached DOM nodes — elements removed from the page but still referenced by a variable or a data structure — can no longer be seen but cannot be collected either.
The tool watches for these statically: it compares your addEventListener calls against your removeEventListener calls and warns when listeners outnumber their teardown, flags setInterval without a matching clearInterval, notices long-lived collections that only ever grow, and points out assignments to window or global that create accidental globals living for the whole page lifetime. These are hints rather than proof — a listener may legitimately live forever — but they are exactly the spots worth checking.
Two tools help you both prevent and confirm leaks. WeakMap and WeakSet hold their keys weakly: if the only remaining reference to an object is the one inside a WeakMap, the object can still be collected, which makes them ideal for associating metadata with DOM nodes or component instances without pinning them in memory. For confirmation, nothing beats the browser's Memory profiler: take a heap snapshot, interact with the app, take another, and compare — growing retained size or a climbing count of detached nodes pinpoints the leak. The durable cure, though, is teardown discipline: every listener you add, every timer you start and every subscription you open should have a matching cleanup that runs when the component unmounts, so references are released the moment they are no longer needed.
Frontend performance engineering
Performance engineering is less about clever micro-optimisations and more about a disciplined process: decide what matters to users, measure it honestly, fix the biggest offenders, and guard the gains so they do not regress. JavaScript sits at the centre of this because it is the resource that most often holds up interactivity, and the tool's analyzer and Web Vitals guidance are designed to feed that loop with concrete, code-level signals rather than vague advice.
It starts with the critical rendering path — the sequence of work the browser must complete to turn HTML, CSS and JavaScript into pixels. Render-blocking and parser-blocking scripts sit directly on that path, so the first lever is to get JavaScript out of the way of the first paint: defer or async non-critical scripts, load below-the-fold logic on interaction, and prefer server rendering or streaming so meaningful content appears before hydration runs. Prioritisation follows naturally — load what the first view needs now, and everything else later.
The RAIL model gives the targets a name. Response: handle user input within 100ms so interactions feel instant. Animation: produce each frame within roughly 16ms to hold 60fps. Idle: use idle time to do deferred work in chunks so it never blocks input. Load: get the page interactive quickly, ideally within a few seconds on a mid-range device. RAIL reframes performance around what the user perceives — responsiveness and smoothness — rather than abstract numbers, and every guideline maps back to keeping the main thread free.
Measuring is non-negotiable, because intuition about performance is famously unreliable. Run Lighthouse for a lab snapshot of your metrics and opportunities, use the Chrome DevTools Performance panel to record a trace and find the long tasks and expensive functions, and watch the Coverage panel to see how much shipped code never executes. Pair lab data with field data (real-user monitoring) so you optimise for actual devices, not just your fast laptop. Finally, set performance budgets — a cap on bundle size, a ceiling on Total Blocking Time, a target for each Core Web Vital — and enforce them in CI so a careless dependency or an oversized import fails the build instead of silently shipping. Budgets turn performance from a one-off cleanup into a property the codebase maintains over time, and the static signals this tool reports — file size, complexity, nested loops, leftover console statements — are exactly the kind of early warnings worth wiring into that process.
Core Web Vitals & JavaScript
Core Web Vitalsare Google's standardised, user-centric measurements of real-world page experience, and they feed directly into search ranking. Three are the headline metrics — LCP, INP and CLS — supported by diagnostics such as TBT and FCP. Because JavaScript is the resource that most often monopolises the main thread, it has a direct hand in nearly all of them. The Web Vitals tab inspects your code for the patterns that commonly hurt each metric and returns targeted recommendations, so you fix problems at the source rather than guessing.
| Metric | Good threshold | JavaScript-level fix |
|---|---|---|
| LCP | ≤ 2.5 s | Ship less JS; minify, split & defer; server-render |
| INP | ≤ 200 ms | Break long tasks; debounce; move work to a Worker |
| CLS | ≤ 0.1 | Reserve space; avoid inserting DOM late after load |
| TBT | ≤ 200 ms | Tree-shake & code-split to cut parse/compile cost |
| FCP | ≤ 1.8 s | Remove render-blocking scripts; strip console/debugger |
LCP (Largest Contentful Paint) measures how long the largest above-the-fold element takes to render, and oversized JavaScript hurts it by competing with the main content for the main thread. The fixes are to ship less code — minify, tree-shake and code-split so the initial bundle is small — defer non-critical scripts, and server-render or stream so content paints before hydration. INP (Interaction to Next Paint) captures overall responsiveness: it suffers when long tasks block the thread while a user is trying to interact, so break heavy functions into smaller chunks, debounce and throttle expensive handlers, and move CPU-heavy work to a Web Worker.
CLS (Cumulative Layout Shift) quantifies unexpected movement of content; JavaScript causes it by inserting DOM above existing content after load — ads, banners, late-rendered widgets — so reserve space for anything that arrives asynchronously and avoid shifting what is already on screen. TBT (Total Blocking Time) is the lab proxy for INP and is driven almost entirely by long tasks during load, which tree shaking and code splitting reduce by cutting parse and compile cost. FCP (First Contentful Paint) marks the first moment any content appears, helped most directly by removing render-blocking scripts and stripping console and debugger statements and dead code from production builds.
This tool brings that entire workflow into one place, all client-side. You can safely minify with granular, conservative-by-default, ASI-aware options and beautify minified or machine-generated JavaScript back into readable code. You can analyze structure — functions, variables, classes, imports and exports, loops, conditionals and nesting — and validate brackets, strings and templates. On top of that sit the quality, security, performance and complexity scores out of 100 with itemised checks, a framework detector for React, Next.js, Vue, Nuxt, Angular, Svelte, Express and NestJS, plus memory and Core Web Vitals guidance, a sandboxed live execution environment to verify behaviour, and CommonJS↔ESM conversion — everything running 100% in your browser with nothing uploaded. It is worth being honest about the boundary, though: variable mangling, dead-code elimination and tree shaking require a full parser, scope analysis and code generator, so for maximum compression you should run a dedicated build tool such as Terser or esbuild in your pipeline — and use this tool for instant, safe minification, auditing, learning and verifying what that build output should look like.
Frequently asked questions
JavaScript minification removes characters a browser does not need to run your code — comments, indentation, blank lines and redundant whitespace — producing a smaller file that downloads and parses faster. This tool performs safe, lossless minification entirely in your browser: the behaviour of your code is unchanged and nothing is uploaded.
Paste, type, upload or drag-and-drop your JavaScript into the editor and the minified output appears instantly with the exact bytes and percentage saved. Toggle options such as removing comments, console statements and debugger statements, then copy or download the result. Everything runs locally.
Yes. Smaller scripts transfer faster and the JavaScript engine parses and compiles fewer bytes, improving load time and reducing Total Blocking Time — especially on mobile and slow networks. The benefit compounds with gzip/Brotli compression, HTTP caching and code splitting.
Not with this tool’s safe approach. The crucial risk in JS minification is automatic semicolon insertion (ASI): deleting a newline the parser relied on can change behaviour. This minifier never removes a source newline that ASI could depend on — it strips comments, indentation, blank lines and redundant spaces while preserving statement boundaries — so the output behaves identically.
Safe minification typically removes 20–50% of formatted source (indentation, comments and blank lines are the biggest wins), and far more after gzip/Brotli. Aggressive build-time tools that also rename variables (see below) can go further. The tool shows the exact bytes and percentage saved for your input.
No — and that is deliberate. Identifier mangling, dead-code elimination and tree shaking require a full parser, scope analysis and code generator (Terser, esbuild, Closure Compiler). Approximating them with heuristics in the browser risks silently breaking code. This tool does safe, lossless minification and instead *analyses* your code for dead-code, complexity and tree-shaking opportunities. For maximum compression, run Terser or esbuild in your build pipeline.
Minification removes redundant characters from the source. Compression (gzip or Brotli) is a server-side byte-level encoding the browser transparently decompresses. They are complementary: minify to remove redundancy, then serve compressed. Minified JS also compresses slightly better.
Remove comments (keeping /*! license comments), collapse whitespace and blank lines, remove debugger statements, and remove standalone console.* calls. Each is a toggle so you control exactly what changes, and the output stays behaviour-preserving.
Yes. Toggle “remove debugger” to strip debugger statements, and “remove console” to delete standalone console.log/info/warn/error calls (calls used as an expression value are kept so logic is not altered). Both are common production-cleanup steps.
Yes. The Beautify tab re-indents minified or messy JavaScript into clean, readable code with your chosen indentation — the inverse of minifying. It is ideal for inspecting production bundles or tidying copied snippets before editing.
Tree shaking is dead-code elimination at the module level: a bundler statically analyses ES module imports/exports and drops exports that are never imported anywhere, so unused library code never ships. It requires ES modules (import/export) and a bundler (esbuild, Rollup, webpack, Vite). This tool flags unused-export and dead-import signals it can detect statically.
Minify and compress; tree-shake with ES modules; code-split with dynamic import() so routes load on demand; lazy-load rarely-used features; replace heavy dependencies with lighter or native APIs; and remove dead code, console and debugger statements. The analyzer and Web Vitals tabs surface where the biggest wins are.
Dead code elimination removes code that can never execute or whose result is never used — unreachable branches after a return, unused variables and functions, and unimported exports. Safe, complete elimination needs a compiler with scope analysis; this tool detects common signals (unused declarations, unreachable patterns) and recommends running a bundler to remove them.
Yes. The Analyze tab reports functions, variables, classes, imports/exports, loops, conditionals, cyclomatic complexity and nesting depth, plus Quality/Health, Complexity and Performance scores (0–100, A–F) with itemised checks and suggestions — a fast structural and quality X-ray of any script.
Cyclomatic complexity counts the number of independent paths through code — roughly one plus the number of decision points (if, for, while, case, catch, &&, ||, ?:). Higher numbers mean more branches to test and reason about. The analyzer reports total and per-function complexity so you can refactor the hot spots.
Yes. The Security tab flags risky patterns with line numbers and a severity: eval() and the Function constructor, innerHTML/outerHTML/insertAdjacentHTML and document.write sinks (XSS), string arguments to setTimeout/setInterval, hardcoded secrets and API keys, shell execution, prototype access and insecure http:// URLs — each with a recommended fix and an overall security score.
It starts at 100 and deducts points by severity — high-severity findings (eval, hardcoded secrets, shell execution) cost the most, medium (DOM XSS sinks) less, and low (hardening notes) least. It is a static-analysis heuristic to catch obvious risks quickly, not a replacement for a full SAST tool or security review.
Yes. The detector recognises React, Next.js, Vue, Nuxt, Angular, Svelte, Express and NestJS from import patterns and APIs, returns a confidence score, and gives framework-specific optimization tips — such as using dynamic imports and Server Components in Next.js, or memoising components in React.
It surfaces common leak patterns statically: addEventListener without a matching removeEventListener, setInterval without clearInterval, ever-growing long-lived collections, and accidental globals. These are directional hints — confirm real retention with the browser’s Memory profiler (heap snapshots and detached-node detection).
Ship less JavaScript: minify, tree-shake and code-split so the initial bundle is small (improves LCP and Total Blocking Time); keep tasks short and move heavy work to a Web Worker (improves INP); defer non-critical scripts; and avoid inserting content late (CLS). The Web Vitals tab gives targeted, code-aware recommendations for each metric.
Common causes are event listeners and timers that are never removed, closures that retain large objects, detached DOM nodes still referenced by JS, and global or module-level collections that only grow. The fix is disciplined teardown — remove listeners, clear timers, and drop references when components unmount.
Yes. The Run tab executes your code in a sandboxed iframe (isolated origin, no access to this page or your data) and shows console output, runtime errors and execution time. A watchdog warns if the code runs too long (possible infinite loop) so you can reset it. It is great for quick experiments and verifying snippets.
Yes. Code runs inside an iframe with the sandbox set to allow scripts only — it has an opaque origin, so it cannot read this page’s data, your cookies or localStorage, and cannot make same-origin requests. Console output is relayed back via postMessage. Still, only run code you understand.
Yes. The Convert tab transforms CommonJS to ESM (require → import, module.exports → export) and ESM to CommonJS, and can wrap JSON as an exportable JS module. These are best-effort source transforms covering the common import/export forms — review the output for unusual patterns.
The tokenizer understands modern JavaScript — ES modules, arrow functions, template literals, async/await, optional chaining and spread. It minifies JSX and TypeScript-flavoured source as text (preserving it), but it does not compile JSX/TS to JavaScript; use Babel, esbuild or tsc for that, then minify the output here.
Yes. Safe minification only removes characters that do not affect execution and preserves all statement boundaries, so the program’s behaviour, output and side effects are identical. The Run tab lets you verify the original and minified code produce the same result.
It handles multi-megabyte files comfortably in the browser, with files up to 100MB accepted. Tokenisation is a single pass and nothing is uploaded, so there is no network bottleneck. For very large bundles, minification is best automated in your build.
Completely. All tokenising, minifying, analysis, auditing and conversion run locally in your browser using JavaScript — your code is never uploaded, logged or stored remotely. That makes the tool safe for proprietary and unreleased code.
Yes. It is 100% free with no sign-up, no usage limits and no watermarks. Minify, beautify, analyze, audit, run and convert as much JavaScript as you like.
For production apps, automate minification in your build (bundlers run Terser/esbuild). This online tool is ideal for one-off files, snippets, learning, auditing third-party code, security spot-checks, running experiments and verifying what your build output should look like.
Terser and esbuild are build-time compilers that also mangle names and eliminate dead code for maximum compression. This tool gives instant, safe, lossless minification in the browser — no install — plus an analyzer, quality/security/performance/complexity scores, framework detection, memory and Web Vitals guidance, a live execution sandbox and module conversion in one place.
Yes. Comments beginning with /*! or containing @license or @preserve are kept even when “remove comments” is on, matching the convention used by build tools so legal notices survive minification.
var is function-scoped and hoisted, which causes subtle bugs; let and const are block-scoped and must be declared before use. const also prevents reassignment. Modern code should prefer const by default and let when reassignment is needed — the Quality audit flags var usage.
== performs type coercion before comparing (so 0 == "" is true), which leads to surprising bugs. === compares value and type without coercion. The Quality audit counts loose comparisons so you can switch to strict equality.
Code splitting breaks a bundle into smaller chunks loaded on demand — typically per route or per feature via dynamic import(). The initial download stays small (better LCP and Total Blocking Time) and rarely-used code loads only when needed. Bundlers do this automatically when you use import().
Use the browser DevTools Coverage panel to see executed vs unused bytes at runtime, and a bundler’s tree-shaking plus tools like the bundle analyzer to find unimported exports. This tool flags static signals — unused declarations, dead imports and unreachable patterns — to point you at candidates.
Indirectly and positively. Search engines do not rank by source formatting, but the faster load times and better Core Web Vitals that smaller, faster JavaScript enables are ranking and user-experience signals. Minification never changes what the page renders.
A long task is any JavaScript that occupies the main thread for over 50ms, during which the page cannot respond to input — the main driver of poor INP. Break long tasks into smaller chunks, defer non-critical work, and offload heavy computation to a Web Worker.
Yes. The tokenizer recognises ?., ??, ??=, ?.(, spread/rest (...), exponentiation (**), logical assignment and other modern operators, so minifying and analysing current-generation code works correctly.
Yes. Because everything runs client-side, the tool keeps working without a connection once loaded, and the interface is fully responsive — the editor and output stack on small screens and the panels adapt.
Code-split routes and heavy components with dynamic import()/React.lazy, prefer Server Components (Next.js) to ship less client JS, memoise expensive renders, tree-shake and replace heavy dependencies, then minify and compress. The framework detector tailors these tips to what it finds in your code.
Related Tools
Explore More Tools
Go ad-free & unlock power features
- Zero ads, faster focused workflow
- Upload 50MB+ files & batch process
- Priority AI type & schema generation