Babel
Add Babel only when you need transforms or plugins that SWC does not cover. Keep SWC as the default pipeline, then scope Babel to the files that need it.
When Babel is a good fit
- You depend on Babel-only plugins or presets.
- You are migrating an existing Babel-heavy project incrementally.
- You want targeted transforms for specific file types (for example MDX).
Babel capabilities
| Capability |
What it gives you |
| Targeted transforms |
Run Babel for specific file types (for example MDX) without replacing the full build pipeline |
| Plugin ecosystem access |
Use Babel-only presets/plugins from existing web projects |
| Incremental migration |
Move legacy Babel extension projects to Extension.js in smaller steps |
| Rspack integration hook |
Configure Babel through extension.config.* config hook |
Example setup
Install Babel dependencies:
npm install -D @babel/core @babel/preset-env babel-loader
Create babel.config.json:
{
"presets": ["@babel/preset-env"]
}
Wire Babel into extension.config.js for MDX only:
export default {
config: (config) => {
config.module.rules.push({
test: /\.mdx$/,
use: ["babel-loader", "@mdx-js/loader"],
});
return config;
},
};

Replace SWC for JS/TS only if required
Use this pattern only when you need Babel to process JS/TS entry files directly:
export default {
config: (config) => {
config.module.rules = [
{
test: /\.[jt]sx?$/,
exclude: /node_modules/,
use: [{ loader: "babel-loader" }],
},
...config.module.rules.filter(
(rule) => !String(rule?.test || "").includes("[jt]sx"),
),
];
return config;
},
};
Best practices
- Prefer targeted Babel usage before replacing the default JS/TS pipeline.
- Keep Babel rules explicit so loader ordering stays predictable.
- Reuse Babel only where migration or plugin compatibility requires it.
Next steps