Diagnosing Rollup Tree-Shaking Failures: Why Unused Code Persists in Bundles
Rollup tree-shaking removes dead code, but unused exports often persist. This guide diagnoses the conditions, provides a cause table, ordered checks, and fixes to reclaim bundle size.
07 Aug 2026, 00:47 UTC

Recognizable condition
After building with Rollup, the production bundle contains functions, classes, or modules that your code never references. Despite using ES module syntax import/export, the code remains, inflating bundle size.\n\n
Diagnostic table: common symptoms and causes
| Symptom | Likely cause | Rollup behavior |
|---|---|---|
| Unused functions remain | Module has side effects (e.g., global assignments) | Rollup preserves the module to avoid runtime breakage |
| Entire library included for one function | CommonJS require/module.exports format | Static analysis fails on dynamic require() |
| Class methods never removed | Prototype-based methods with dynamic access | Bundler cannot guarantee methods won't be called via strings |
| Code persists despite ESM usage | Dynamic imports or unresolved property paths | Bundler cannot determine required code at build time |
Ordered checks to identify the root cause
Verify module format. Rollup requires raw ES modules. If Babel or TypeScript compiles to CommonJS before Rollup runs, tree-shaking is impossible. Check tsconfig.json or Babel config for module: 'commonjs' and switch to module: 'ESNext'.
Inspect the sideEffects flag. By default, Rollup assumes every imported module might have side effects. Add a sideEffects property to package.json to mark effect-free files, or list specific patterns such as *.css or ./src/init.js.
Run the bundle visualizer. Install @rollup/plugin-visualizer and generate an interactive map to see which modules occupy space and why.
Check for dynamic patterns. Evaluate whether class methods are accessed via string keys or prototype manipulation. If so, consider refactoring into standalone functions that Rollup can more easily track.
Fixes tied to findings
If side effects are the cause, explicitly mark them using sideEffects rather than setting it to false globally, which can break initialization code.
If CommonJS is detected, ensure the pipeline outputs ES modules for Rollup to process. A build step that converts ESM to CJS before Rollup will nullify tree-shaking.
For class-heavy libraries, refactor public methods into pure functions where possible. Functions have clearer static-call graphs for the bundler.
Address dynamic imports by ensuring import paths are static and resolvable. Avoid computed import() calls when the goal is maximum tree-shaking.
Escalation criteria
If the bundle still contains unexpected code after applying the checks above, investigate whether third-party dependencies ship CommonJS or use runtime feature detection. In such cases, consider rollup-plugin-commonjs with include restrictions, or assess if the bundle size trade-off is acceptable for the convenience of the dependency.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.