Answer
For a low‑traffic workload that can assume modern browsers, the recommended configuration is:
targets: a browserslist query that covers the last two versions of each major browser or, equivalently, 0.25%, not dead'.
useBuiltIns: 'usage' (injects only the polyfills actually used).
corejs: 3 for full ES‑next support; 2 if you are certain you only need ES2015‑ES2019 features and want a slightly smaller core‑js footprint.
ignoreBrowserslistConfig: set to true in a package‑specific babel.config.js to override a repository‑wide .browserslistrc without affecting other packages.
Confirmed Facts
- The
targets option is evaluated at compile time; any change requires a full rebuild.
useBuiltIns: 'usage' forces Babel to statically analyse the entire codebase, which increases build time but yields the smallest possible bundle.
- Core-js version 3 includes polyfills for all ECMAScript proposals up to the current stage, while version 2 stops at ES2019.
ignoreBrowserslistConfig: true in a package’s Babel config prevents that package from reading the project‑wide .browserslistrc, allowing a local override.
Likely Explanation (Trade‑off)
Choosing a targets query like 0.25%, not dead' or the explicit last‑two‑versions list excludes browsers that collectively represent less than a quarter of a percent of traffic. For a low‑traffic site this usually means you can drop polyfills for very old browsers (e.g., IE11, old Safari) while still covering the vast majority of users. Pairing that with useBuiltIns: 'usage' ensures Babel only injects the polyfills your code actually needs, minimizing bundle size. The extra static‑analysis cost is typically acceptable for low‑traffic projects where bundle size impacts user experience more than occasional longer builds.
If you are confident that your code only uses features standardized up to ES2019, switching to corejs: 2 can shave a few kilobytes off the core‑js payload without losing functionality for the targeted modern browsers. However, this omits polyfills for newer proposals (e.g., logical assignment operators, top‑level await) that those browsers already support natively, but could become necessary if you later target a browser version that still needs a polyfill for a newer feature.
In a monorepo, placing ignoreBrowserslistConfig: true inside a specific package’s babel.config.js lets that package use its own targets (or a different browserslist query) while other packages continue to respect the shared .browserslistrc. This avoids conflicts as long as the override is intentional and documented.
Steps to Apply the Recommendation
- Decide on the browser coverage you need. If you have usage data, pick a threshold (e.g., >0.25%); otherwise start with the last two versions of Chrome, Firefox, Safari, and Edge.
- In your project’s root
babel.config.js (or per‑package config), set:
module.exports = {
presets: [
['@babel/preset-env', {
targets: '>0.25%, not dead', // or explicit list like 'Chrome >= 90, Safari >= 14, Firefox >= 88, Edge >= 90'
useBuiltIns: 'usage',
corejs: 3 // change to 2 if you only need ES2015‑ES2019
}]
]
};
- For a package that needs different targets, add
ignoreBrowserslistConfig: true to its babel.config.js and define its own targets.
- Run a production build and measure bundle size with a tool such as
webpack-bundle-analyzer or rollup-plugin-visualizer.
- Measure build duration (e.g., via
time or CI timestamps) and compare to a baseline with useBuiltIns: false or 'entry'.
- Test the built app in a browser matrix matching your targets (using BrowserStack, Sauce Labs, or local VMs) to confirm no missing polyfills cause runtime errors.
When to Re‑evaluate (Missing Diagnostic Detail)
The above recommendation assumes that the share of legacy browsers is negligible. If you discover—via analytics or server logs—that a noticeable portion of users (e.g., >0.5%) still relies on a browser excluded by your targets (such as Safari 13 or an older Edge version), you should widen the targets or fall back to useBuiltIns: 'entry' to avoid runtime errors. Therefore, the one missing diagnostic detail that could change the recommendation is the actual browser usage distribution for your audience.
Summary
Use a modest browserslist threshold (>0.25% or last two versions), useBuiltIns: 'usage', and corejs: 3 (or 2 if ES2019 suffices) to achieve the smallest bundle with an acceptable build‑time overhead for low‑traffic workloads. Override shared browserslist settings per package with ignoreBrowserslistConfig: true when needed, and verify the assumption about legacy‑browser usage before finalizing the target list.