| description | This document lists all breaking changes from Rsbuild 1.x to 2.0. Use it as a migration reference. |
|---|
import { PackageManagerTabs } from '@theme';
This document lists all breaking changes from Rsbuild 1.x to 2.0. Use it as a migration reference.
If you are using a Coding Agent that supports Skills, install the rsbuild-v2-upgrade skill to help with the upgrade process from v1 to v2.
npx skills add rstackjs/agent-skills --skill rsbuild-v2-upgradeAfter installation, let the Coding Agent guide you through the upgrade.
-
Upgrade
@rsbuild/coreto the 2.0 RC release. -
If you use
@rsbuild/plugin-reactor@rsbuild/plugin-svgr, upgrade them to the 2.0 RC release as well to keep them compatible with@rsbuild/core. For example:
{
"devDependencies": {
"@rsbuild/core": "^2.0.0-rc.0",
"@rsbuild/plugin-react": "^2.0.0-rc.0",
"@rsbuild/plugin-svgr": "^2.0.0-rc.0"
}
}- For other Rsbuild plugins, we recommend upgrading to the latest version too:
# Upgrade Rsbuild dependencies in the current directory
npx taze major --include /rsbuild/ -w
# Or recursively upgrade Rsbuild dependencies in the entire monorepo
npx taze major --include /rsbuild/ -w -rRsbuild v2 now depends on @rspack/core v2. If you use custom Rspack configurations or plugins, you may need to make corresponding adjustments.
See the Rspack v2 upgrade guide for all breaking changes.
In Rsbuild 2.0, the default browserslist have been updated to better reflect the modern web platform baseline.
The default web browserslist has moved to a more modern baseline, the new default corresponds to baseline widely available on 2025-05-01:
- Chrome 87 → 107
- Edge 88 → 107
- Firefox 78 → 104
- Safari 14 → 16
This change affects JavaScript and CSS transformations, as well as polyfill behavior.
If your project defines its own browserslist configuration, for example via .browserslistrc or package.json#browserslist, Rsbuild will continue to use it. The defaults only apply when no browserslist configuration is found.
To keep the previous behavior, create a .browserslistrc file in your project root:
chrome >= 87
edge >= 88
firefox >= 78
safari >= 14
Rsbuild 2.0 also updates the default Node.js target. Since Node.js 18 reached end of life in April 2025, Rsbuild now defaults to Node 20+.
- Node 16 → 20
To keep the previous behavior, use output.overrideBrowserslist:
export default {
output: {
target: 'node',
overrideBrowserslist: ['node >= 16'],
},
};Rsbuild 2.0 requires Node.js 20.19+ or 22.12+, Node.js 18 is no longer supported.
@rsbuild/core is now published as a pure ESM package, and its CommonJS build output has been removed. This change only affects how Rsbuild itself is published, reducing the installation size by about 500 KB.
In Node.js 20 and later, the runtime natively supports loading ESM modules via require(esm). As a result, for most projects that use Rsbuild through its JavaScript API, this change should have no practical impact and does not require any code modifications.
This does not affect Rsbuild's ability to build CommonJS output. All related build behavior and configuration options remain unchanged.
core-js polyfill has been changed from a default dependency of @rsbuild/core to an optional peer dependency, which reduces the installation size by 1.2 MB.
If you enabled output.polyfill, install core-js v3 in your project:
If you use the moduleFederation.options option, install @module-federation/runtime-tools manually in your project. In Rsbuild v2, it is an optional peer dependency of @rspack/core:
This change only affects projects that use Module Federation v1.5 through moduleFederation.options. If you are using Module Federation v2, no action is required.
The default value of server.host has changed from '0.0.0.0' to 'localhost'.
This change prevents the dev server from being exposed to the local network by default, ensuring "secure by default" behavior.
If you need to access the server from other devices on the same network (e.g., for mobile testing), you can manually set the host to '0.0.0.0':
export default {
server: {
host: '0.0.0.0',
},
};Alternatively, you can use the --host CLI flag to enable network access on demand:
rsbuild --hostThe default value of source.decorators.version has changed from 2022-03 to 2023-11.
For most projects, this change has little practical impact. If your project depends on the previous default behavior, set the decorators version explicitly:
export default {
source: {
decorators: {
version: '2022-03',
},
},
};When output.target is set to node, Rsbuild 2.0 defaults to ESM output via output.module and keeps output.minify disabled. In Rsbuild 1.x, the default was CommonJS output with minification enabled.
This keeps Node bundles aligned with modern ESM conventions while preserving clearer stack traces for debugging.
As a result, your runtime needs to load ESM bundles (for example, set "type": "module" in package.json or use .mjs output) unless you opt back into CommonJS.
To restore v1 behavior, explicitly disable ESM output and enable minification:
export default {
output: {
target: 'node',
module: false,
minify: true,
},
};The deprecated source.alias option has been removed. Use resolve.alias instead.
export default {
- source: {
+ resolve: {
alias: {
'@': './src',
},
},
};The deprecated source.aliasStrategy option has been removed. Use resolve.aliasStrategy instead.
export default {
- source: {
+ resolve: {
aliasStrategy: 'prefer-alias',
},
};The deprecated performance.bundleAnalyze option has been removed.
In earlier versions, Rsbuild bundled webpack-bundle-analyzer by default. Rsdoctor now provides built-in bundle size analysis, so this functionality no longer needs to live inside @rsbuild/core. Removing it also helps reduce the installation size.
Use Rsdoctor to analyze bundle size, or register webpack-bundle-analyzer yourself via tools.rspack:
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
export default {
tools: {
rspack: {
plugins: [
new BundleAnalyzerPlugin({
analyzerMode: 'static',
}),
],
},
},
};The performance.removeMomentLocale option has been removed.
This option existed to drop Moment.js locale data from the bundle, but Rspack v2 does not include Moment locales by default, so the option is no longer necessary.
For background, see web-infra-dev/rsbuild#6991.
The performance.profile option has been removed. If you relied on it to emit a stats JSON file, use stats.toJson() in a custom plugin instead:
import { writeFileSync } from 'node:fs';
import { join } from 'node:path';
const statsJsonPlugin = {
name: 'stats-json-plugin',
setup(api) {
api.onAfterBuild(({ stats }) => {
writeFileSync(
join(api.context.distPath, 'stats.json'),
JSON.stringify(stats?.toJson({}), null, 2),
);
});
},
};
export default {
plugins: [statsJsonPlugin],
};performance.chunkSplit is deprecated in Rsbuild 2.0, but not removed yet, so it still works.
We recommend migrating to the new splitChunks option. It aligns with Rspack's optimization.splitChunks and provides presets that mirror performance.chunkSplit.strategy.
strategy: 'split-by-experience'→splitChunks.preset: 'default'
export default {
- performance: {
- chunkSplit: {
- strategy: 'split-by-experience',
- },
- },
+ splitChunks: {
+ preset: 'default',
+ },
};strategy: 'split-by-module'→splitChunks.preset: 'per-package'
export default {
- performance: {
- chunkSplit: {
- strategy: 'split-by-module',
- },
- },
+ splitChunks: {
+ preset: 'per-package',
+ },
};strategy: 'single-vendor'→splitChunks.preset: 'single-vendor'
export default {
- performance: {
- chunkSplit: {
- strategy: 'single-vendor',
- },
- },
+ splitChunks: {
+ preset: 'single-vendor',
+ },
};strategy: 'all-in-one'→ disable chunk splitting
export default {
- performance: {
- chunkSplit: {
- strategy: 'all-in-one',
- },
- },
+ splitChunks: false,
};strategy: 'custom'+splitChunks→splitChunks.preset: 'none'
export default {
- performance: {
- chunkSplit: {
- strategy: 'custom',
- splitChunks: {
- // ...
- },
- },
- },
+ splitChunks: {
+ preset: 'none',
+ // ...
+ },
};strategy: 'split-by-size'→ configureminSize/maxSizedirectly
export default {
- performance: {
- chunkSplit: {
- strategy: 'split-by-size',
- minSize: 20000,
- maxSize: 50000,
- },
- },
+ splitChunks: {
+ preset: 'none',
+ minSize: 20000,
+ maxSize: 50000,
+ },
};override→splitChunksdirectly
export default {
- performance: {
- chunkSplit: {
- override: {
- // ...
- },
- },
- },
+ splitChunks: {
+ // ...
+ },
};forceSplitting is syntactic sugar for cacheGroups, so you can replace it directly with cacheGroups:
export default {
- performance: {
- chunkSplit: {
- forceSplitting: {
- axios: /node_modules[\\/]axios/,
- },
- },
- },
+ splitChunks: {
+ cacheGroups: {
+ axios: {
+ test: /node_modules[\\/]axios/,
+ name: 'axios',
+ chunks: 'all',
+ priority: 0, // Use 1 when using single-vendor preset
+ enforce: true,
+ },
+ },
+ },
};Rsbuild has upgraded its dependency on http-proxy-middleware from v2 to v4 and some options have changed.
You can follow the examples below to migrate your config, or check the http-proxy-middleware v3 breaking changes for more details.
- The
contextoption is replaced bypathFilter:
export default {
server: {
proxy: [
{
- context: '/api',
+ pathFilter: '/api',
target: 'https://example.com',
},
],
},
};- Proxy events are now configured in a unified way using the
onoption:
export default {
server: {
proxy: {
'/api': {
- onOpen: () => {},
- onClose: () => {},
- onError: () => {},
- onProxyReq: () => {},
- onProxyRes: () => {},
+ on: {
+ open: () => {},
+ close: () => {},
+ error: () => {},
+ proxyReq: () => {},
+ proxyRes: () => {},
+ },
},
},
},
};- Removed the deprecated
compilerparameter fromrsbuild.build(). - Removed the deprecated
compilerparameter fromrsbuild.startDevServer(). - Removed the deprecated content-changed message type from
sockWrite. Usefull-reloadinstead. - Renamed
rsbuild.onAfterStartProdServermethod torsbuild.onAfterStartPreviewServer - Renamed
rsbuild.onBeforeStartProdServermethod torsbuild.onBeforeStartPreviewServer - The default value of the
loaderparameter of loadConfig method has changed fromjititoauto, preferring the native Node.js loader.
- Renamed
api.onAfterStartProdServerhook toapi.onAfterStartPreviewServer - Renamed
api.onBeforeStartProdServerhook toapi.onBeforeStartPreviewServer
Rsbuild 2.0 no longer supports using webpack as the bundler. In Rsbuild 1.x, this capability was mainly used to validate compatibility between Rspack and webpack. As Rspack has gradually matured and stabilized, this purpose is no longer necessary, so the related support has been removed.
The specific changes are as follows:
- Removed the
@rsbuild/webpackpackage. - Removed the
@rsbuild/plugin-webpack-swcpackage. - Removed the
providerconfiguration option. - Removed the
tools.webpackandtools.webpackChainconfiguration options. - Removed the
api.modifyWebpackChainandapi.modifyWebpackConfigplugin hooks. - Removed the
webpacktype from theapi.context.bundlerType. - Removed webpack-related types.
The built-in JS and CSS transform rules now use oneOf to separate different branches. If you customized the JS or CSS rules with tools.bundlerChain or api.modifyBundlerChain, you may need to adjust your configuration.
The built-in JS rule is now split into two oneOf branches:
CHAIN_ID.ONE_OF.JS_MAIN: for SWC transformsCHAIN_ID.ONE_OF.JS_RAW: for?rawimports
If you previously added loaders on CHAIN_ID.RULE.JS, move them to the JS_MAIN branch:
export default {
tools: {
bundlerChain(chain, { CHAIN_ID }) {
const jsRule = chain.module.rule(CHAIN_ID.RULE.JS);
- jsRule.use('my-loader').loader('my-loader');
+ jsRule
+ .oneOf(CHAIN_ID.ONE_OF.JS_MAIN)
+ .use('my-loader')
+ .loader('my-loader');
},
},
};The built-in CSS rule is split into three oneOf branches:
CHAIN_ID.ONE_OF.CSS_MAIN: normal CSS transformsCHAIN_ID.ONE_OF.CSS_RAW: for?rawimportsCHAIN_ID.ONE_OF.CSS_INLINE: for?inlineimports
If you previously added loaders on CHAIN_ID.RULE.CSS, move them to the CSS_MAIN branch:
export default {
tools: {
bundlerChain(chain, { CHAIN_ID }) {
const cssRule = chain.module.rule(CHAIN_ID.RULE.CSS);
- cssRule.use('my-css-loader').loader('my-css-loader');
+ cssRule
+ .oneOf(CHAIN_ID.ONE_OF.CSS_MAIN)
+ .use('my-css-loader')
+ .loader('my-css-loader');
},
},
};The built-in rules in the Less/Sass/Stylus plugins have the same oneOf change, so update customizations to use the corresponding ONE_OF branches there as well.
- The query parameter
?__inline=falsehas been removed, use?urlinstead. - The
dev.setupMiddlewaresoption is deprecated, use server.setup instead. style-loaderhas been upgraded from v3 to v4, and some options oftools.styleLoaderhave changed. See the style-loader v4.0.0 release notes for details.- The deprecated template parameters have been removed from
html.templateParameterswebpackConfig: userspackConfiginstead.htmlWebpackPlugin: usehtmlPlugininstead.
- If you customized Rsbuild logs with the global
logger.override(), switch to customLogger in v2. Instance loggers in v2 are no longer affected by the globallogger.override().