Tree shaking is a dead code elimination technique used by JavaScript bundlers to remove unused code from the final output file at build time, resulting in a smaller and faster-loading bundle.
The term comes from the mental image of shaking a tree so that dead leaves fall away, leaving only what is alive and connected. In practice, a bundler analyzes the dependency graph of a JavaScript application and identifies which exported functions, classes, or variables are actually imported and used somewhere in the codebase. Any code that is exported but never referenced is considered "dead" and is excluded from the final bundle.
Tree shaking relies on the static structure of ES Modules (the import and export syntax introduced in ES2015). Because ES Module imports and exports are declared at the top level and cannot be conditional, a bundler can determine at build time - without executing the code - exactly which parts of a module are needed. This is in contrast to the older CommonJS require() system, which is dynamic and makes static analysis significantly harder.
Popular bundlers such as webpack, Rollup, and esbuild all support tree shaking to varying degrees. Rollup, in particular, was one of the first tools to popularize the technique and remains known for producing especially lean output. For tree shaking to work effectively, the code being processed must be written using ES Module syntax, and library authors are encouraged to ship their packages in this format for the same reason.
Tree shaking is closely related to other bundle optimization strategies. Minification reduces file size by rewriting code into a more compact form, while code splitting divides a bundle into smaller chunks that can be loaded on demand. Tree shaking complements both: it ensures that even the code which does get bundled contains no unnecessary exports before minification is applied.
The practical impact of tree shaking is most visible when working with large utility libraries. If a project imports only a single helper function from a library that exports hundreds, a well-configured bundler will include only that one function in the final file. This keeps JavaScript payloads lean, which directly benefits page load performance and, by extension, user experience and Core Web Vitals scores.
It is worth noting that tree shaking has limits. Code with side effects - meaning code that performs an action simply by being imported, such as modifying a global variable - cannot always be safely removed, even if its exports go unused. Bundlers rely on a sideEffects field in a package's package.json file, or on their own analysis, to determine whether a module is safe to exclude.