Configure Babel preset-env with useBuiltIns: usage for selective polyfilling
Learn how to set up Babel preset-env with useBuiltIns: usage to transpile ES2015+ code while injecting only the polyfills actually needed for your target browsers.
04 May 2026, 22:07 UTC

Desired outcome
Transpile modern JavaScript with Babel while injecting only the polyfills that are actually needed for the declared target environments, keeping the final bundle as small as possible.
Prerequisites
- Node.js version 14 or newer.
- npm or yarn available in the project.
- A source directory (e.g.,
src/) containing ES2015+ code. - No existing Babel configuration that conflicts with
@babel/preset-env.
Procedure
- Install the required packages:
# Run in the project root npm install --save-dev @babel/core @babel/preset-env core-js@3 # or with yarn yarn add -D @babel/core @babel/preset-env core-js@3 - Create a Babel configuration file named
.babelrc(orbabel.config.json) in the project root with the following content:{ "presets": [ [ "@babel/preset-env", { "targets": ">0.25%, not dead", "useBuiltIns": "usage", "corejs": 3 } ] ] }Explanation:
targetsdefines the browsers or environments you support; the example covers browsers with >0.25% global usage that are not officially dead.useBuiltIns: "usage"tells Babel to analyze each file and import only the polyfills required by the features actually used in that file.corejs: 3matches the version of thecore-jspackage installed.
- Add a build script to
package.json(if not already present):"scripts": { "build": "babel src --out-dir lib --copy-files" } - Run the build:
npm run build # or yarn run buildThis will transpile files from
src/tolib/, inserting selectivecore-jsimports where needed.Expected checks
- Inspect a generated file in
lib/(e.g.,lib/example.js). You should see:- Transpiled syntax (e.g., arrow functions turned into
functionexpressions). - Import statements like
import "core-js/modules/es.array.map";only for features actually used in the source file. - No imports for polyfills that correspond to features already supported by your targets (e.g.,
Promiseif targeting modern browsers).
- Transpiled syntax (e.g., arrow functions turned into
- Optional: compare bundle sizes before and after enabling
useBuiltIns: "usage"using a tool likewebpack --profileorrollupwith the same targets. Expect a reduction in the size contributed bycore-js. - Run the built code in a target browser (e.g., Chrome 80) or via a test suite that exercises the transpiled features. The console should show no warnings about missing polyfills.
Recovery options
If you encounter runtime errors indicating a missing polyfill:
- Verify that the
targetslist truly includes the environment where the error occurs. Adjust the query (e.g., addIE 11) and rebuild. - If your code uses dynamic
import()orevalthat Babel cannot statically analyze, switch to theentrymode:{ "presets": [ ["@babel/preset-env", { "targets": ">0.25%, not dead", "useBuiltIns": "entry", "corejs": 3 }] ] }Then add a single import at your application entry point:
import "core-js/stable"; import "regenerator-runtime/runtime";This guarantees all polyfills for the targets are included, at the cost of a larger bundle.
- Ensure the version of
core-jsinstalled matches thecorejsnumber in the preset; mismatches can cause runtime errors. Reinstall withnpm install core-js@3if needed.
- Inspect a generated file in
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.