Tree shaking is a static analysis optimization in JavaScript bundlers that eliminates unused exports from the final production bundle to reduce file size.
Tree Shaking is a form of dead code elimination (DCE) implemented in modern JavaScript and TypeScript module bundlers (such as Webpack, Rollup, Vite, and esbuild). The term was originally popularized by the Rollup module bundler; it draws an analogy to shaking a physical tree until dead or disconnected leaves fall to the ground, leaving only the living, essential branches intact.
In JavaScript applications, tree shaking relies on the static structure of ECMAScript 6 (ES2015) Modules (import and export statements). Because ES module imports and exports cannot be dynamically computed or altered at runtime, bundlers can build a complete Abstract Syntax Tree (AST) of module dependencies, determine which exported functions or variables are never referenced by the application graph, and safely discard them from the final production bundle.
Inspect module dependencies, verify tree-shaking efficacy, and identify bloated CommonJS libraries using our interactive Bundle Size Analyzer, optimize compiled output with the JS Minifier, or inspect production bundle mappings using the Source Map Explorer.
| Specification | Details |
|---|---|
| Primary Requirement | ECMAScript Modules (ESM / import / export) |
| Incompatible Formats | CommonJS (require / module.exports), UMD, AMD |
| Configuration Standard | package.json with "sideEffects": false |
| Supported Bundlers | Webpack 5+, Rollup 4+, Vite 5+, esbuild, Turbopack |
| Performance Impact | Reduces bundle download payload, V8 AST parse time, and TBT |
Because import statements must reside at top-level module scope, the bundler determines imports before running any code:
// utils/math.ts
export function add(a: number, b: number): number {
return a + b;
}
export function multiply(a: number, b: number): number {
return a * b; // If never imported, this function is completely excluded
}
// app.ts
import { add } from './utils/math';
console.log(add(2, 3));
During bundling, multiply() is pruned from the production output.
CommonJS allows conditional and dynamic loading at runtime:
// Cannot be statically analyzed by bundlers safely
const moduleName = getDynamicName();
const helper = require(moduleName);
if (condition) {
module.exports = { a: 1 };
}
Because CommonJS exports can mutate at runtime, bundlers must include the entire library, even if only a single method is utilized.
package.json "sideEffects"A module has a side effect if it executes operations that affect global state or browser APIs when imported (such as modifying window, injecting CSS styles, or polyfilling Promise).
By default, bundlers conservatively preserve modules if there is any chance importing them triggers a side effect. By adding "sideEffects": false in your package.json, you guarantee to the bundler that re-exports without direct usage can be safely pruned.
{
"name": "my-ui-library",
"version": "1.0.0",
"sideEffects": [
"*.css",
"*.scss"
]
}
index.ts that re-exports 500 components can defeat tree-shaking if third-party bundler transforms do not preserve export boundaries. Prefer direct deep imports or configure "sideEffects": false.export default { add, multiply }) prevents bundlers from dropping individual methods because object properties can be accessed dynamically (obj[prop]). Always prefer named exports (export function add).@babel/preset-env transforms import/export into require/module.exports before Webpack or Rollup analyzes the code, tree shaking is completely disabled. Set { "modules": false } in your Babel configuration.Minification (performed by tools like Terser, esbuild, or SWC) removes whitespace, shortens variable names, and eliminates simple unreachable code branches within a function (such as if (false)). Tree shaking, in contrast, performs cross-module dependency graph pruning, eliminating entire unused functions, classes, and third-party files.
import { debounce } from 'lodash'?Standard lodash is distributed as CommonJS. Importing named members from lodash still bundles the full ~72 KB library. To enable tree-shaking, install lodash-es (import { debounce } from 'lodash-es') or import the direct sub-path (import debounce from 'lodash/debounce').
Generate a Webpack stats file or production source map and load it into our Bundle Size Analyzer or Source Map Explorer to inspect the exact constituent modules present in your compiled chunks.
Free, browser-based utilities to test, generate, and inspect Tree Shaking & Dead Code Elimination in JavaScript Bundlers payloads directly.
Analyze and visualize JavaScript bundle sizes with optimization suggestions.
Format, minify, and validate JavaScript code instantly.
Resolve minified stack traces back to original source code using source maps.