babel-loader: the webpack adapter that runs Babel on your source
📦 Babel loader for webpack
At a glance
- What is it?
- The Babel project's official webpack and Rspack loader, a thin layer whose real substance is cache invalidation, version compatibility and a troubleshooting section written by people who have debugged it.
- Who is it for?
- babel-loader is a thin package with a disproportionate reputation for causing confusion, and reading the README explains why. Almost every complaint about it comes from one of three places: a `test` regex that is transforming `node_modules`, a cache that is not keyed to what you changed, or a version mismatch between the loader, webpack, Node and Babel.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 35 days ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 7, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A compatibility table worth reading first
The first substantive thing in the README is a table mapping loader versions to the webpack, Babel and Node versions they support, and it is the fastest way to resolve a version problem:
| babel-loader | webpack | Babel | Node.js | | 8.x | 4.x or 5.x | 7.x | >= 8.9 | | 9.x | 5.x | ^7.12.0 | >= 14.15.0 | | 10.x | ^5.61.0 | ^7.12.0 or ^8.0.0-alpha | ^18.20.0 or ^20.10.0 or >=22.0.0 |
Two rules follow from it. The `main` branch README is for v8, v9 and v10 with Babel 7 and above; anyone on legacy Babel v6 is pointed at the `7.x` branch docs. And the current line, 10.x, needs a recent Node, which is why the jump from v9 to v10 was a breaking change rather than a routine release.
`package.json` in the repository confirms what the table promises. The package version is 10.1.1, `engines.node` is `^18.20.0 || ^20.10.0 || >=22.0.0`, and the peer dependencies are `@babel/core` at `^7.12.0 || ^8.0.0-beta.1`, `@rspack/core` at `^1.0.0 || ^2.0.0-0` and webpack at `>=5.61.0`. Both `@rspack/core` and webpack are marked optional in `peerDependenciesMeta`, which is how one loader can support two bundlers without forcing either on you. The single runtime dependency is `empathic`, a small module-resolution helper.
Installation and the minimum webpack rule
Installation is one command, and it installs more than the loader:
npm install -D babel-loader @babel/core @babel/preset-env webpackThe four packages are all required, which is a common stumble. `@babel/core` is the compiler and `@babel/preset-env` is what decides which syntax gets transformed for which targets, so a project with only `babel-loader` installed cannot work.
The configuration itself is a standard module rule. The `test` regex covers `.js`, `.mjs` and `.cjs`, `exclude` skips `node_modules`, and the loader receives `targets: "defaults"` with `@babel/preset-env`:
module: {
rules: [
{
test: /\.(?:js|mjs|cjs)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
targets: "defaults",
presets: [
['@babel/preset-env']
]
}
}
}
]
}The option object is passed straight through to Babel and merged with whatever config files Babel finds, such as `babel.config.js` or `.babelrc`. That merging behaviour is the thing to internalise: what you write under `options` is not the complete Babel configuration, it is one input to it.
The loader-specific options and what the cache keys on
Most options belong to Babel and are documented on babeljs.io. Four are the loader's own, and the caching trio is the part that matters day to day.
`cacheDirectory` defaults to `false`. Set to a directory, it caches transform results on disk so subsequent builds skip the recompilation. Set to `true`, it uses `node_modules/.cache/babel-loader`, falling back to the OS temporary directory if no `node_modules` folder is found in any root. The README claims this can speed things up by as much as twice.
`cacheIdentifier` defaults to a string built from the versions of `@babel/core` and `babel-loader`. The final cache key adds the input file path, the merged Babel config as computed by `Babel.loadPartialConfigAsync`, and that identifier. The merged config is derived from `babel.config.js` or `.babelrc` if they exist, otherwise from `BABEL_ENV` and `NODE_ENV`. Overriding `cacheIdentifier` is the documented way to force a cache bust.
`cacheCompression` defaults to `true`, gzipping each transform output, and can be turned off if you transpile thousands of files.
The fourth option, `customize`, defaults to `null` and takes the path of a module exporting a `custom` callback. The README advises against it and suggests `.custom` on a wrapper loader instead, keeping this one only for projects that must keep calling `babel-loader` directly. `metadataSubscribers` takes an array of context function names, allowing a webpack plugin to receive Babel metadata through hooks, with `./test/metadata.test.js` given as the example.
Why your build is slow, in the author's own diagnosis
The troubleshooting section opens with the most common complaint and gives it a one-sentence cause: make sure you are transforming as few files as possible. The likely cause, it says, is a `test` regex that matches more than you intended, such as matching `node_modules`. The fix is the `exclude` option in the loader config, and the second fix is `cacheDirectory` for up to a twofold improvement.
That is a better answer than most, because it identifies the actual mechanism rather than suggesting a faster machine. A `test` of `/\.m?js$/` is the common way this happens, and it is easy to miss that the regex has no negative condition on the path.
For debugging in general, the README points at webpack's `stats.loggingDebug` option rather than adding its own verbosity switch:
// webpack.config.js
module.exports = {
// ...
stats: {
loggingDebug: ["babel-loader"]
}
}That ordering matters. Debug logging first to see what is being compiled, then fix the rule. The v10 release notes confirm this was a deliberate addition: a babel-loader logger shipped in 10.0.0 and a README section on `loggingDebug` support was added alongside it.
The node_modules exception pattern for legacy targets
There is a scenario where skipping `node_modules` is wrong: a dependency ships modern syntax and your targets are old enough that the browser cannot parse it. The README calls this out specifically for IE 11 and offers a pattern that excludes the directory while carving out named exceptions.
{
test: /\.(?:js|mjs|cjs)$/,
exclude: {
and: [/node_modules/], // Exclude libraries in node_modules ...
not: [
// Except for a few of them that needs to be transpiled because they use modern syntax
/unfetch/,
/d3-array|d3-scale/,
/@hapi[\\/]joi-date/,
]
},The `and` plus `not` shape is a webpack condition object rather than a plain regex, and it is worth internalising independently of this loader. It is the general form of the answer to selective transpilation, and the README also mentions passing a function to `exclude` or using a negative lookahead as alternatives.
The last entry in the troubleshooting section is about Babel injecting helpers into every file, which is a different complaint with a different cause: Babel's small helpers for functions like `_extend` are added per file by default. The README's remedy there is configuration rather than loader settings, so if that is your symptom, the answer is not in babel-loader.
What the v10 releases changed
The release history shows a project moving deliberately toward Babel 8. v10.0.0, published 2025-02-27, carried the two breaking changes: Node raised to `^18.20.0 || ^20.10.0 || >=22.0.0` and webpack to `>= 5.61.0`, plus using webpack's `output.hashFunction` as the loader's cache hasher. That second change is the subtle one, since it ties cache keys to your webpack configuration. The same release added the logger, added caching with external dependencies, and fixed filename cache-key stability.
v10.1.0 on 2026-03-06 is where the Babel 8 work landed: type checking enabled and Babel 8 support added in one pull request, webpack marked as an optional peer dependency in another, and CI pinned to specific Node versions. The remaining entries are dependency bumps handled by dependabot, for `js-yaml`, webpack itself, `glob` and `minimatch`.
v10.1.1 on 2026-03-09 is a single-line revert of the `module.findPackageJSON` usage from 10.1.0, which is a good illustration of why the release granularity matters for something as central as a bundler loader. The repository is not archived and the last push was on 2026-09-03, so the 10.x line is still receiving work. Tests run through `node --test` with `c8` coverage and a `lint-staged` precommit hook, which explains why a project this small can still carry a `codecov.yml`.
Editorial conclusion
babel-loader is a thin package with a disproportionate reputation for causing confusion, and reading the README explains why. Almost every complaint about it comes from one of three places: a `test` regex that is transforming `node_modules`, a cache that is not keyed to what you changed, or a version mismatch between the loader, webpack, Node and Babel. The compatibility table in the README settles the third of those immediately, and the cache options settle the second once you know that `cacheIdentifier` is computed from the merged Babel config and the loader and Babel versions. The troubleshooting section is the part most people skip and most people need, because the slow-build advice is really an `exclude` diagnosis. Where to start is the version table, then the option list, then the IE 11 entry if your targets are old: that one shows how to exclude `node_modules` except for a named few, which is the pattern almost every mature webpack config converges on.
Frequently asked questions
Which version of babel-loader should I install?
Use 10.x for a current setup. The README's table maps 10.x to webpack `^5.61.0`, Babel `^7.12.0` or `^8.0.0-alpha`, and Node `^18.20.0`, `^20.10.0` or `>=22.0.0`. If you are on legacy Babel v6, the docs for the `7.x` branch are the relevant ones.
Why is babel-loader slowing down my webpack build?
The usual cause is a `test` regex matching more than intended, often `node_modules`. Exclude that directory in the rule, and set `cacheDirectory` to cache transform results on disk, which the README says can improve speed by as much as twice.
Does babel-loader work with Rspack as well as webpack?
Yes. The README describes the package as transpiling JavaScript together with webpack or Rspack, and `package.json` lists `@rspack/core` as an optional peer dependency alongside webpack, so neither bundler is forced on you.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/babel-babel-loader)