{"post":{"slug":"what-is-tree-shaking-2026","title":"What Is Tree Shaking in 2026? Dead Code Elimination","excerpt":"Tree shaking removes code your bundle never uses, but only if it can prove that safely. Here is how the static analysis behind it works, and where it quietly fails in 2026.","category":"code","date":"July 24, 2026","author":"ByteLedger Team","content":"<span class=\"dropcap\">T</span>ree shaking is what a bundler does when it looks at every export in your codebase, traces which ones are actually imported anywhere, and deletes the rest before shipping the final bundle. The name comes from the mental image of shaking a tree so the dead leaves, the code nothing depends on, fall away. It sounds automatic, and often it is, but it only works under specific conditions. The moment those conditions break — a CommonJS module in the chain, a barrel file, a missing package.json field — dead code stops falling and quietly rides along in your bundle instead.\n\n## What changed in 2026\n\n- **Rollup and esbuild-based tooling made tree shaking closer to default-on.** Vite and similar modern build tools now tree shake without much manual configuration, where older webpack setups often needed explicit tuning.\n- **Bundle analyzers became a common CI step**, catching size regressions automatically rather than relying on someone noticing the bundle got bigger.\n- **More npm packages ship proper sideEffects metadata**, since bundle size increasingly affects page performance scores that feed into search visibility, giving package authors a direct incentive to mark their code side-effect free.\n- **Barrel file costs got wider recognition.** More style guides and linters now flag deep barrel re-exports as a real performance risk, not just a style preference.\n\n## How tree shaking actually works\n\n```javascript\n// math.js\nexport function add(a, b) { return a + b; }\nexport function multiply(a, b) { return a * b; }\n\n// main.js\nimport { add } from \"./math.js\";\nconsole.log(add(2, 3));\n```\n\n`multiply` is never imported, so a tree-shaking bundler can prove it is unreachable and drop it from the final bundle entirely. This only works because import and export statements are static — the bundler can see the whole dependency graph without executing any code.\n\n## Why CommonJS blocks it\n\n```javascript\n// CommonJS - opaque to static analysis\nconst math = require(\"./math.js\");\nconsole.log(math.add(2, 3));\n```\n\nA bundler cannot safely prove which properties of `math` actually get used, since `require` is a normal function call and `module.exports` is just an object that code elsewhere could mutate. Tree shaking is largely limited to the ES module parts of your dependency graph.\n\n## The barrel file problem\n\nA barrel file re-exports many modules through one entry point. Importing a single named export from it can still pull in everything the barrel touches, because evaluating the barrel means evaluating every file it re-exports from, unless side-effect metadata or deeper bundler analysis proves the rest is safe to skip.\n\n```javascript\n// icons/index.ts (barrel file)\nexport * from \"./home-icon\";\nexport * from \"./search-icon\";\nexport * from \"./settings-icon\";\n// ...200 more icons\n\n// consuming file\nimport { HomeIcon } from \"./icons\";\n```\n\nEven though only `HomeIcon` is used, some bundler configurations will still evaluate or include the other icon modules. Importing directly from the specific file instead of the barrel avoids the problem entirely.\n\n## What helps and what hurts\n\n| Practice | Effect on tree shaking |\n| --- | --- |\n| ES module import/export syntax | Enables it |\n| CommonJS require/module.exports | Mostly blocks it |\n| \"sideEffects\": false in package.json | Helps the bundler drop unused files confidently |\n| Deep barrel file re-exports | Often hurts, can pull in far more than needed |\n| Named exports instead of one default export object | Helps, each export is tracked individually |\n| Top-level code with side effects, like logging on import | Hurts, the bundler cannot safely remove it |\n\n## How to verify it is actually working\n\nDo not assume tree shaking is happening just because the code is written with `import`/`export`. Run a source-map based bundle analyzer to see what actually shipped, remove an export you believe is unused and confirm the bundle shrinks, and track bundle size in CI over time so a regression shows up immediately instead of months later.\n\n## FAQ\n\n**Does tree shaking work automatically with any bundler?**\nMost modern bundlers support it, but only for ES module code and only when they can prove a piece of code is unused and safe to remove. It does not work regardless of how the code is written.\n\n**Why is my unused code still in the bundle?**\nThe most common causes are a CommonJS module somewhere in the dependency chain, a barrel file re-exporting more than you use, or a missing sideEffects field that forces the bundler to keep files it cannot prove are safe to drop.\n\n**Is tree shaking the same as minification?**\nNo. Minification shrinks the code that remains, by shortening names and removing whitespace. Tree shaking removes entire pieces of code that are never used, before minification even runs.\n\n**Does tree shaking work with dynamic imports?**\nYes, code loaded through a dynamic import is analyzed the same way. Dynamic import is more often used for a related but different goal — see [what is code splitting in 2026](/blog/what-is-code-splitting-2026) for how it defers loading code rather than removing it.\n\n## Where to go next\n\n- [What is code splitting in 2026](/blog/what-is-code-splitting-2026)\n- [What is lazy loading in 2026](/blog/what-is-lazy-loading-2026)\n- [What is a virtual DOM in 2026](/blog/what-is-a-virtual-dom-2026)","hue":290,"metaTitle":"Tree Shaking Explained 2026: Dead Code Elimination","metaDescription":"Tree shaking explained for 2026: how bundlers remove unused code via static analysis, why commonjs blocks it, and the barrel file problem.","keywords":["tree shaking 2026","what is tree shaking","dead code elimination javascript","tree shaking webpack vite rollup","sideeffects package json","esm vs commonjs tree shaking","barrel file tree shaking","named exports tree shaking","reduce bundle size javascript"],"tldr":["**Tree shaking removes exports that are never imported anywhere** — it works through static analysis of import and export statements, not by running the code.","**It requires ES modules, not CommonJS** — require calls are dynamic and opaque to the bundler, so CommonJS code mostly defeats tree shaking.","**The sideEffects field in package.json tells the bundler what is safe to drop** — without it, a bundler has to assume any imported file might have side effects and keep it.","**Barrel files quietly defeat tree shaking in practice** — a single index file re-exporting a whole folder can force a bundler to include far more than you actually import.","**Skip:** assuming your bundle is tree-shaken just because you use import and export syntax — verify with a bundle analyzer, do not assume."],"readTime":"4 min read","wordCount":860},"related":[{"slug":"what-is-code-splitting-2026","title":"What Is Code Splitting in 2026? Bundles Explained","excerpt":"Code splitting breaks one large JavaScript bundle into smaller chunks loaded only when needed. Here is how dynamic import and route-based splitting actually work in 2026.","category":"code","date":"July 22, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":280},{"slug":"how-to-reduce-bundle-size-2026","title":"How to reduce bundle size in 2026: tree-shaking, code splitting, and audits","excerpt":"A large JavaScript bundle is a direct tax on every user load. Here is the 2026 guide to finding what bloats your bundle and cutting it without breaking things.","category":"code","date":"February 26, 2026","author":"ByteLedger Team","readTime":"5 min read","hue":321},{"slug":"what-is-the-event-loop-2026","title":"What is the event loop in 2026? Tracing code step by step","excerpt":"The event loop decides what runs next when your code has a call stack, a microtask queue, and a callback queue all waiting. Here is how to trace it.","category":"code","date":"July 24, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":290}],"sameCategory":[{"slug":"bazel-build-explained-2026","title":"Bazel Explained: What Hermetic Builds Actually Cost","excerpt":"Bazel delivers reproducible, precisely cached builds and demands that you describe everything. Here is what you get, what it costs, and who should say no.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":145},{"slug":"graphql-federation-2026","title":"GraphQL Federation: One Graph, Many Teams","excerpt":"Federation composes independently-owned subgraphs into a single API. Here is what it solves, the operational cost it adds, and when a simpler gateway is enough.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":300},{"slug":"hermetic-builds-explained-2026","title":"Hermetic Builds Explained: Same Inputs, Same Output","excerpt":"A hermetic build depends only on declared inputs. Here is what that property gives you, the common leaks that break it, and how to move toward it incrementally.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":130},{"slug":"monorepo-tooling-compared-2026","title":"Monorepo Tooling Compared: What You Actually Need","excerpt":"Monorepo tools solve task orchestration and caching, not repository layout. Here is what each tier provides and how to tell when you have outgrown the simple option.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":150}],"newer":{"slug":"what-is-transformer-architecture-2026","title":"What Is Transformer Architecture in 2026? Full Breakdown","excerpt":"The transformer is the architecture behind nearly every modern language model. Here is a practitioner-level breakdown of its parts and why each one exists.","category":"ai","date":"July 24, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":240},"older":{"slug":"what-is-two-phase-commit-2026","title":"What Is Two-Phase Commit in 2026: The Protocol Explained","excerpt":"Two-phase commit is the classic protocol for making a transaction atomic across multiple nodes. Here is the 2026 guide to how prepare and commit phases work, why it can block, and when a saga is the better call.","category":"code","date":"July 24, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":290}}