Optimizing Bundle Size with Rollup Tree-Shaking
Learn how to leverage Rollup's tree-shaking to eliminate dead code from your bundles. Discover the importance of named exports and the risks of the sideEffects flag.
30 Oct 2025, 18:21 UTC

The Bloat Problem in Modern Libraries
When building a utility library or a UI component kit, you often provide a wide array of functions to cover various use cases. However, a consumer of your library might only need one specific helper function. Without an efficient way to prune unused code, the end-user downloads the entire library, increasing load times and memory usage. This is the problem tree-shaking solves.
The Takeaway: Rollup uses static analysis of ES module (ESM) imports and exports to identify "dead code"—code that is defined but never actually called—and excludes it from the final bundle. To maximize this, you must use ESM syntax and explicitly manage side effects.
How Rollup Identifies Dead Code
Unlike traditional minifiers that look for unreachable code blocks (like code after a return statement), Rollup's tree-shaking operates at the module level. It builds a dependency graph of your imports and exports. If a function is exported from utils.js but no other module in the entry chain imports it, Rollup treats that function as dead code.
This process relies on the static nature of ES modules. Because import and export statements must happen at the top level of a file, Rollup can determine what is being used without actually running the code. This is why CommonJS (module.exports and require) is significantly harder to tree-shake; those calls can happen dynamically inside conditionals or loops, making it impossible for a bundler to be certain if a piece of code is truly unused.
Practical Implementation: The ESM Pattern
To ensure your code is tree-shakable, avoid exporting a single large object containing all your utilities. Instead, use named exports.
Inefficient Pattern (The "God Object")
// mathUtils.js
export default {
add: (a, b) => a + b,
subtract: (a, b) => a - b
};
In the example above, if a user imports only add, Rollup may still include the entire object (including subtract) because the object is a single entity.
Efficient Pattern (Named Exports)
// mathUtils.js
export const add = (a, b) => a + b;
export const subtract = (a, b) => a - b;
With named exports, Rollup can surgically remove subtract if it is never imported elsewhere in the application.
Configuration and Verification
Tree-shaking is enabled by default in Rollup. However, you can fine-tune the behavior in your rollup.config.js. For aggressive pruning, you can use the treeshake property.
// rollup.config.js
export default {
input: 'src/index.js',
output: { file: 'dist/bundle.js', format: 'esm' },
treeshake: 'smallest' // Uses a more aggressive preset to minimize bundle size
};
Verifying the Result
To verify that tree-shaking is working, follow these steps on your local development machine:
- Create a module with two functions: one used in your entry point and one that is never imported.
- Run the build command (e.g.,
npx rollup -c). - Search the resulting
dist/bundle.jsfor the name of the unused function. If it is absent, tree-shaking succeeded. - To confirm the difference, set
treeshake: falsein your config, rebuild, and verify that the unused function now appears in the output.
The "Side Effects" Trap
The biggest limitation of tree-shaking is side effects. A side effect is any code that modifies something outside its own scope when the module is first loaded—for example, modifying a global variable, adding a listener to window, or initializing a polyfill.
Rollup is conservative. If it suspects a module has side effects, it will include the entire module even if no exports are used, because removing it might break the application's behavior. You can signal to Rollup that your package is side-effect free by adding this to your package.json:
{
"name": "my-library",
"sideEffects": false
}
Warning: Be cautious. If you mark "sideEffects": false but your library actually performs critical initialization on load (like setting up a global CSS theme), Rollup will strip that code away, leading to runtime errors or missing styles that are difficult to debug.
Summary Checklist
- Use ESM: Stick to
export const ...rather thanexport default { ... }. - Avoid CommonJS: If you must use CommonJS dependencies, use
@rollup/plugin-commonjs, but be aware it may hinder pruning. - Declare Side Effects: Use the
sideEffectsfield inpackage.jsonto help the bundler make confident decisions. - Inspect Output: Regularly check your bundle contents or use a visualizer plugin to ensure dead code is actually being removed.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.