@maru

NestJS 12 Rspack Migration — Boosting Monorepo Build Speed
NestJS 12 is phasing out Webpack support in its official CLI, introducing Rspack, a Rust-based, high-speed bundler, as the official build tool. Now that build speed has become a critical factor in the development productivity of large monorepos, switching to Rspack is a very welcome change. However, replacing your existing build system can easily lead to challenging technical hurdles, such as missing SWC decorator metadata or class name obfuscation in production builds. I've put together a practical guide to help you smoothly resolve these real-world migration issues in your NestJS 12-based monorepo environment and maximize the benefits of adopting Rspack.
Benefits of Switching to Rspack: Why Replace Webpack?
NestJS 12 has dropped support for Webpack, which had long been central to the official CLI, and adopted Rspack as the new official build tool. In large-scale monorepo environments, Webpack's slow compilation and heavy hot reloads were the biggest bottlenecks disrupting developer flow. Rspack solves this by dramatically boosting build performance while maintaining excellent compatibility with the Webpack architecture and configuration framework.
According to the official announcement from Trilon Consulting, NestJS 12 provides a modern, high-speed toolchain featuring Vitest, oxlint, and Rspack, alongside a transition to native ESM. Thanks to this change, developers can significantly reduce cold starts and latency during source code changes, even in large backend codebases. The ability to easily harness the overwhelming performance of a Rust bundler while retaining most of the existing Webpack plugin ecosystem is the primary reason for this migration.
Key Hurdle 1: Restoring SWC Decorator Metadata
To maximize build speed, Rspack uses the built-in SWC loader builtin:swc-loader to compile TypeScript code instead of the default tsc. While this dramatically improves build performance, it creates a critical barrier in NestJS environments: runtime errors. This is because dependency injection, a core mechanism of NestJS, relies on decorator metadata.
Since SWC does not generate decorator metadata during compilation by default, dependency injection will fail completely unless explicit configurations are added. To solve this, you must enable the legacyDecorator and decoratorMetadata options for the SWC loader in your Rspack configuration file.
rspack.config.mjs You can fully restore metadata by customizing the loader settings in your
// rspack.config.mjs
export default {
module: {
rules: [
{
test: /\.ts$/,
use: {
loader: 'builtin:swc-loader',
options: {
jsc: {
parser: { syntax: 'typescript', decorators: true },
transform: { legacyDecorator: true, decoratorMetadata: true }
}
}
}
}
]
}
};If this setting is not applied, the application will experience runtime crashes because it cannot identify dependencies during startup. Therefore, this is an essential checkpoint to verify immediately when starting your Rspack migration.
Key Hurdle 2: Preventing Class Name Obfuscation in Production Builds
The biggest pitfall when performing production builds with Rspack is the obfuscation of class and function names. The default minifier provided by Rspack shortens internal identifiers to random characters to minimize file size. However, NestJS frequently uses the actual class name and reference as an identifier when generating dependency injection tokens or executing methods like context.getClass() to look up the execution context. If class names are changed arbitrarily, runtime guards or service instances may not be correctly identified, leading to abnormal routing blocking or dependency resolution failures.
To prevent this malfunction, you must ensure that the build toolchain preserves the original names of classes and functions. You can do this by manually editing the SwcJsMinimizerRspackPlugin optimization settings to enable compress and mangle rules, specifically activating the keep_classnames and keep_fnames properties.
Here is an example optimization to ensure production stability for your NestJS application through Rspack configuration.
// rspack.config.mjs (Rspack 1.x 및 NestJS 12 기준)
import { rspack } from '@rspack/core';
export default {
optimization: {
minimizer: [
new rspack.SwcJsMinimizerRspackPlugin({
minimizerOptions: {
compress: { keep_classnames: true, keep_fnames: true },
mangle: { keep_classnames: true, keep_fnames: true }
}
})
]
}
};Adding this setting ensures that the compiler preserves the original class name structure during code minification. This maintains the consistency of the NestJS engine's metadata mapping, even after production deployment.
Key Hurdle 3: HMR Socket Conflicts and EADDRINUSE Errors
To fully enjoy Rspack's incredible build speed in a development server, enabling Hot Module Replacement (HMR) is essential. However, applying this to the backend can lead to port contention errors. Because HMR replaces only modules while keeping the process alive, the network socket used by the previous application instance may not close properly, resulting in EADDRINUSE errors.
To prevent this completely, utilize NestJS's application lifecycle management to explicitly terminate the existing instance right before the module is swapped. If you have set up your HMR environment using @rspack/core/hot/poll?100 and run-script-webpack-plugin in an Rspack environment, you must insert lifecycle cleanup logic into your main entry point file, main.ts.
Here is the main.ts configuration for safely rebooting backend instances in development without socket conflicts.
// main.ts (NestJS 12 / Rspack HMR 대응)
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
declare const module: any;
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3000);
if (module.hot) {
module.hot.accept();
module.hot.dispose(() => app.close());
}
}
bootstrap();By calling module.hot.dispose inside the app.close() callback, you ensure that the active HTTP server socket is cleanly terminated before new code is applied, creating a smooth and fast HMR experience.
Configuring Custom Rspack Adapters in an Nx Monorepo
Automatic conversion tools like @nx/rspack:convert-webpack provided by Nx monorepos often cause unexpected issues when migrating Webpack configurations for backend Node applications. Unlike frontend builds, backend builds must consider Node runtime characteristics such as file system access and native module bindings, making manual custom configuration much more stable than relying solely on automated tools.
The key to manual configuration is specifying Node as the build target and preventing external dependencies from being bundled into the output. To achieve this, create an rspack.config.mjs file in your application root and apply nodeExternals to exclude packages in the node_modules folder from the bundle.
Here is an example of a custom Rspack configuration for NestJS running in an Nx environment. It is written for Nx 19 and above.
import { composePlugins, withNx } from '@nx/rspack';
import nodeExternals from 'webpack-node-externals';
export default composePlugins(withNx(), (config) => {
config.target = 'node';
config.externalsPreset = { node: true };
config.externals = [
nodeExternals({
allowlist: [/^@monorepo\//]
})
];
return config;
});Configuring a custom adapter in this way ensures that unnecessary third-party libraries are not included in the bundle. As a result, only the internal shared libraries of your monorepo are included in the compilation, which drastically improves build speed and significantly optimizes your production image size.
Preparing for Rspack Adoption
The combination of NestJS 12 and Rspack is a clear breakthrough for development teams struggling with slow build speeds in large monorepos. I recommend reviewing your migration early using the @nestjs/cli@next pre-release package and checking the decorator metadata and class name preservation settings mentioned above. By validating the stability of your production builds and the local development experience in advance, you can enjoy massive improvements in build speed without any hassle when the official release arrives.
Reference Links