Optimizing Bundle Size with @babel/preset-env and core-js
Learn how to use @babel/preset-env with 'useBuiltIns: usage' to automatically inject only the necessary polyfills, reducing bundle size while maintaining browser compatibility.
10 Oct 2026, 05:33 UTC

The Problem: Polyfill Bloat vs. Browser Compatibility
Developers often face a trade-off when supporting older browsers: either include a massive polyfill library that slows down page loads for everyone, or risk runtime crashes for users on legacy browsers. Manually importing polyfills is error-prone and leads to "dead code"—shipping fixes for features your application doesn't actually use.
The solution is @babel/preset-env configured with useBuiltIns: 'usage'. This approach analyzes your source code and automatically injects only the specific polyfills required by your target browser list, significantly reducing the final bundle size.
How Automated Polyfilling Works
Babel uses a mapping system to correlate JavaScript features (like Promise or Object.assign) with the browser versions that support them. When you define a target environment, Babel determines which syntax needs transpilation (changing the structure of the code) and which features need polyfilling (adding missing functionality via a library like core-js).
Implementation Example
To implement this, you need @babel/preset-env and core-js installed in your project. The configuration is typically handled in a babel.config.json file.
{
"presets": [
[
"@babel/preset-env",
{
"targets": "> 0.25%, not dead, ie 11",
"useBuiltIns": "usage",
"corejs": "3.30"
}
]
]
}
Configuration Breakdown
- targets: Uses a Browserslist query. In this example, it targets browsers with more than 0.25% global usage, those not marked as "dead" by the community, and specifically Internet Explorer 11.
- useBuiltIns: 'usage': This is the critical setting. Instead of importing all polyfills at the start of your app, Babel adds
import "core-js/modules/es.array.includes.js"only in files where.includes()is actually called. - corejs: Specifies the version of
core-jsto use. Version 3 is recommended as it supports instance methods and avoids polluting the global namespace if configured for commonjs.
Comparing Polyfill Strategies
| Option | Mechanism | Bundle Impact | Risk |
|---|---|---|---|
false (default) |
No polyfills added automatically. | Smallest | Runtime errors in old browsers. |
'entry' |
Replaces a single global import with all polyfills needed for targets. | Large | Includes polyfills you may not use. |
'usage' |
Injects imports based on actual code usage. | Optimized | Slightly slower build times due to analysis. |
Critical Limitations and Common Pitfalls
The node_modules Exclusion
By default, most build pipelines (like Webpack or Vite) exclude the node_modules folder from Babel processing to improve build speed. However, if a third-party dependency uses modern JavaScript that your target browsers don't support, useBuiltIns: 'usage' will not see that code, and your app will crash in the browser.
Fix: You must explicitly include specific problematic packages in your Babel loader configuration rather than excluding all of node_modules.
Version Mismatch
If the corejs version specified in babel.config.json does not match the version installed in package.json, Babel may inject imports for modules that do not exist in the installed library, leading to "Module not found" errors during the build process.
Verifying the Result
To ensure your configuration is working as intended, follow these diagnostic steps:
- Check the Output: Run your build command and search the generated JavaScript bundle for the string
"core-js". - Verify Specificity: If you used
Array.prototype.includesin your code, you should see a specific import for that module (e.g.,core-js/modules/es.array.includes) rather than a generic import of the entire library. - Test the Target: Open the application in the oldest browser you support (e.g., IE11 or an old version of Chrome). Check the developer console for
TypeError: Object doesn't support property or method..., which indicates a missing polyfill.
Rollback Procedure
If the automated polyfilling causes build failures or unexpected runtime behavior, revert to manual polyfilling by setting "useBuiltIns": false in your config and adding import "core-js/stable"; to the very top of your main entry file.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.