website/docs/en/guide/migration/rspack_1.x.mdx
import { PackageManagerTabs } from '@theme';
This document lists the breaking changes from Rspack 1.x to 2.0.
If your Coding Agent supports Skills, install the rspack-v2-upgrade skill to help with the migration.
npx skills add rstackjs/agent-skills --skill rspack-v2-upgrade
After installation, let the agent guide you through the upgrade.
@rspack/core to the 2.0 release.@rspack/cli, @rspack/dev-server, or @rspack/plugin-react-refresh, upgrade them to the latest compatible versions so they stay in sync with @rspack/core. For example:{
"devDependencies": {
"@rspack/core": "^2.0.0",
"@rspack/cli": "^2.0.0",
"@rspack/dev-server": "^2.0.0",
"@rspack/plugin-react-refresh": "^2.0.0"
}
}
Rspack 2.0 requires a minimum Node.js version of 20.19+ or 22.12+, and Node.js 18 is no longer supported.
@rspack/core, @rspack/cli, @rspack/dev-server and @rspack/plugin-react-refresh are now published as pure ESM packages, with CommonJS builds removed.
In Node.js 20 and later, the runtime natively supports loading ESM modules via require(esm), so for most projects that use Rspack through its JavaScript API, this change should have no practical impact and does not require code changes.
This does not affect Rspack's ability to build CommonJS output. All related build behavior and configuration remain unchanged.
@rspack/dev-server 2.0 includes the following changes:
@rspack/cli no longer depends on @rspack/dev-server by default, since some workflows do not require a dev server. When using the rspack dev or rspack serve commands, install @rspack/dev-server manually:devServer.proxy and devServer.watchFiles. See the upgrade guide for details.@rspack/dev-server dependencies are now more streamlined and modernized:
webpack-dev-middleware.The built-in webpack-bundler-analyzer has been removed from @rspack/cli, and the --analyze flag is no longer available.
If you need to analyze bundle outputs, it is recommended to use Rsdoctor, which provides more powerful analysis capabilities.
The default value of module.parser.javascript.exportsPresence has been changed from warn to error. When detecting non-existent exports, an error will now be thrown directly instead of just a warning.
If you want to restore the old behavior, you can explicitly set it to auto:
export default {
module: {
parser: {
javascript: {
exportsPresence: 'auto',
},
},
},
};
module.parser.javascript.strictExportPresence has been removed. You can use module.parser.javascript.exportsPresence to control the behavior when exports don't exist.
The default value of module.parser.javascript.requireAlias changed from true to false. If your code relies on renamed require calls being parsed and bundled, explicitly enable it:
export default {
module: {
parser: {
javascript: {
requireAlias: true,
},
},
},
};
In Rspack 2.0, builtin:swc-loader no longer supports reading .swcrc files. Move your SWC configuration into the loader options in rspack.config.js:
export default {
module: {
rules: [
{
test: /\.(?:js|mjs|jsx|ts|tsx)$/,
loader: 'builtin:swc-loader',
options: {
detectSyntax: 'auto',
jsc: {
transform: {
react: {
runtime: 'automatic',
},
},
},
},
},
],
},
};
The rspackExperiments.collectTypeScriptInfo option of builtin:swc-loader has been removed. Use collectTypeScriptInfo to control TypeScript information collection:
export default {
module: {
rules: [
{
test: /\.ts$/,
loader: 'builtin:swc-loader',
options: {
collectTypeScriptInfo: {
typeExports: true,
},
},
},
],
},
};
The rspackExperiments.import option of builtin:swc-loader has been moved to the top-level transformImport option. rspackExperiments.import is still supported as a deprecated alias in Rspack 2.0, but you should migrate to transformImport to avoid future breakage:
export default {
module: {
rules: [
{
test: /\.js$/,
loader: 'builtin:swc-loader',
options: {
- rspackExperiments: {
- import: [
- {
- libraryName: 'antd',
- style: true,
- },
- ],
- },
+ transformImport: [
+ {
+ libraryName: 'antd',
+ style: true,
+ },
+ ],
},
},
],
},
};
In Rspack 2.0, the targets configuration for builtin:swc-loader, builtin:lightningcss-loader, and rspack.LightningCssMinimizerRspackPlugin now defaults to the target configuration. If you need different targets, configure them in the loader or plugin options:
export default {
target: 'node',
module: {
rules: [
{
test: /\.js$/,
loader: 'builtin:swc-loader',
options: {
env: {
targets: 'chrome >= 87',
},
},
},
],
},
};
experiments.pureFunctions for function-level tree shakingRspack 2.0 adds an experimental experiments.pureFunctions switch for finer-grained, pure-function-based tree shaking across modules.
After enabling it, you can choose one of these entry points depending on your code ownership:
node_modules./*#__NO_SIDE_EFFECTS__*/ on function definitions when you can modify the source code directly.export default {
experiments: {
pureFunctions: true,
},
module: {
rules: [
{
test: /node_modules\/some-library\/index.js/,
parser: {
pureFunctions: ['isString'],
},
},
],
},
};
For more details, see the pureFunctions section and the NO_SIDE_EFFECTS annotation in the tree shaking guide.
output.libraryTarget: moved to output.library.typeoutput.libraryExport: moved to output.library.exportoutput.umdNamedDefine: moved to output.library.umdNamedDefineoutput.auxiliaryComment: moved to output.library.auxiliaryCommentThe default value of output.chunkLoadingGlobal changed from webpackChunk${output.uniqueName} to rspackChunk${output.uniqueName}. If your application depends on the old name, configure it explicitly:
export default {
output: {
chunkLoadingGlobal: 'webpackChunkMyApp',
},
};
The default value of output.hotUpdateGlobal changed from webpackHotUpdate${output.uniqueName} to rspackHotUpdate${output.uniqueName}. If your application depends on the old name, configure it explicitly:
export default {
output: {
hotUpdateGlobal: 'webpackHotUpdateMyApp',
},
};
The default value of output.bundlerInfo.force changed from true to false. In Rspack 2.0, __rspack_version__ and __rspack_unique_id__ are injected on demand by default instead of always being added as runtime modules. If your application depends on the previous always-injected behavior, configure it explicitly:
export default {
output: {
bundlerInfo: {
force: true,
},
},
};
The fallback value of output.trustedTypes.policyName changed from 'webpack' to 'rspack'. policyName still defaults to output.uniqueName, and the fallback is only used when uniqueName is not set. If your project relies on the old fallback, update your CSP configuration or set it explicitly:
export default {
output: {
trustedTypes: {
policyName: 'webpack',
},
},
};
The output.charset configuration has been removed. It only added a charset attribute to generated <script> tags, and modern browsers already default to UTF-8.
The optimization.removeAvailableModules configuration has been removed. It had no actual effect in Rspack and can be safely removed from your configuration.
When stats.toJson() is called without parameters, these fields now default to false:
modules: Module informationassets: Asset informationchunks: Chunk informationchunkGroups: Chunk group informationentryPoints: Entry point informationBy default, stats.toJson() no longer includes these details, so the returned object is more compact. If you need them, pass the parameters explicitly:
const statsData = stats.toJson({
modules: true,
assets: true,
chunks: true,
chunkGroups: true,
entryPoints: true,
});
For detailed parameter configuration, refer to Stats.
The top-level profile configuration and stats.profile configuration have been removed. Use Rsdoctor for performance analysis:
export default {
- profile: true,
stats: {
- profile: true,
},
};
The rspack.EsmLibraryPlugin plugin has been removed. Configure output.library to generate ESM output:
-import { EsmLibraryPlugin } from '@rspack/core';
export default {
- plugins: [new EsmLibraryPlugin()],
+ output: {
+ library: {
+ type: 'modern-module',
+ },
+ },
};
WarnCaseSensitiveModulesPlugin has been renamed to CaseSensitivePlugin, which covers all of its functionality.
The getHooks method on HtmlRspackPlugin, RsdoctorPlugin, and RuntimePlugin has been removed. It was only a deprecated alias of getCompilationHooks, so migrate to getCompilationHooks directly.
The sri configuration of HtmlRspackPlugin has been removed. If you need SRI functionality, use the SubresourceIntegrityPlugin plugin.
export default {
plugins: [
new rspack.HtmlRspackPlugin({
- sri: "sha256",
}),
+ new rspack.SubresourceIntegrityPlugin({
+ hashFuncNames: ["sha256"],
+ }),
],
};
The following LightningCssMinimizerRspackPlugin options have changed:
draft: removed; use drafts insteadcssHeadDataCompression: removed; delete this option directlyRspack 2.0 no longer includes .wasm in the default resolve.extensions used for JavaScript requests. That means extension-less requests such as import './module' or require('./module') no longer try ./module.wasm by default, while explicit imports like import './module.wasm' are not affected. If you need the previous behavior, add .wasm back to the corresponding resolve.byDependency entries:
export default {
resolve: {
byDependency: {
esm: {
extensions: ['.js', '.json', '.wasm'],
},
commonjs: {
extensions: ['.js', '.json', '.wasm'],
},
},
},
};
Rspack 2.0 no longer includes webpack in the default CSS @import resolve conditions. If you need the previous behavior, add webpack back explicitly:
export default {
resolve: {
byDependency: {
'css-import': {
conditionNames: ['webpack', '...'],
},
},
},
};
devtool default valueThe default value of the devtool option has changed:
mode is development, the default value of devtool has been changed from eval to cheap-module-source-mapmode is production and you are using @rspack/cli, the default value of devtool has been changed from source-map to falseIf you need source maps in production, set devtool to source-map or hidden-source-map:
const isProd = process.env.NODE_ENV === 'production';
export default {
devtool: isProd ? 'source-map' : 'cheap-module-source-map',
};
The following deprecated properties of Runtime module have been removed:
constructorName - Constructor name propertymoduleIdentifier - Module identifier propertyIf you used these properties in custom plugins, update your code as follows:
class MyPlugin {
apply(compiler) {
compiler.hooks.compilation.tap('MyPlugin', (compilation) => {
compilation.hooks.runtimeModule.tap('MyPlugin', (module) => {
- const name = module.constructorName;
- const id = module.moduleIdentifier;
+ // Use alternative ways to get module information
+ const name = module.constructor.name;
+ const id = module.identifier();
});
});
}
}
The ProgressPlugin custom handler's third argument changed from items: string[] to a structured info object.
- (percent, msg, items) => void
+ (percent, msg, info) => void
info includes:
builtModules: number: Number of modules built so farmoduleIdentifier?: string: Identifier of the module being built (only provided during build modules updates)resolve.rootsThe resolve.roots configuration default value changed from [context] to [].
In Rspack 1.x, resolve.roots implicitly included the project context, so the following CSS import could be resolved as <context>/node_modules/lib/style.css:
@import '/node_modules/lib/style.css';
In Rspack 2.0, this implicit behavior has been removed to align with standard module resolution. Requests starting with / are treated as file-system absolute paths.
Use a package request or a relative path instead:
@import 'lib/style.css';
@import '../node_modules/lib/style.css';
If you do rely on the previous behavior, add the following configuration:
export default {
resolve: {
roots: [import.meta.dirname],
},
};
readResourceForScheme hookNormalModule.getCompilationHooks(compilation).readResourceForScheme has been removed. This hook was only a legacy alias for readResource.for(scheme), so migrate to that API directly.
@module-federation/runtime-tools is declared as optional peerDependencyThe @module-federation/runtime-tools package has changed from dependencies to optional peerDependencies (declared via peerDependencies + peerDependenciesMeta.optional). If you are using ModuleFederationPlugin, ensure that this package is explicitly installed in your project.
module.unsafeCachemodule.unsafeCache was previously a performance optimization option. Because it conflicts with Rspack's Incremental Build and Persistent Cache mechanisms, it has been officially removed.
experiments.css has been removed. CSS processing capability is now available by default, but you still need to configure the corresponding type in module.rules to enable it:
export default {
module: {
rules: [
{
test: /\.css$/,
type: 'css/auto', // Auto-detect CSS Modules
},
],
},
};
Available type options:
css: Process CSS as plain CSS, without CSS Modulescss/module: Force enable CSS Modulescss/auto: Auto-detect, enable CSS Modules for .module.css files, and process plain .css files as regular CSSFor more details, refer to CSS
The default value of experiments.asyncWebAssembly changed from false to true. Files with the .wasm extension will now be handled using the built-in webassembly/async rule. If you don't need this feature, you can explicitly disable it:
export default {
experiments: {
asyncWebAssembly: false,
},
};
experiments.cache: moved to the top-level cache.experiments.rspackFuture: removed; bundlerInfo has moved to output.bundlerInfo.experiments.incremental: moved to the top-level incremental.experiments.layers: removed; layers are now stable and enabled by default, but you still need to configure layer in module.rules.experiments.topLevelAwait: removed; top-level await is now stable and enabled by default in ESM modules.experiments.lazyCompilation: moved to the top-level lazyCompilation.experiments.lazyCompilationMiddleware: moved to the top-level lazyCompilationMiddleware.experiments.lazyBarrel: removed; the Lazy barrel optimization is now enabled by default.experiments.typeReexportsPresence: removed; use module.parser.javascript.typeReexportsPresence directly to control the behavior when re-exporting types.experiments.inlineConst: removed; use optimization.inlineExports to control constant inlining optimization.experiments.inlineEnum: removed; use optimization.inlineExports and builtin:swc-loader's collectTypeScriptInfo.exportedEnum to control enum inlining optimization.experiments.outputModule: removed; use output.module directly to output ESM artifacts.experiments.parallelLoader: removed; loader parallelization is now stable and enabled by default, but you still need to configure module.rules.use.parallel to opt in.experiments.SubResourceIntegrityPlugin: moved to the top-level SubresourceIntegrityPlugin.