System Info
System:
- OS: Ubuntu 22.04.5 LTS (Linux 6.8.0 azure)
- CPU: (16) x64 AMD EPYC 7763
- Memory: 62 GB
Binaries:
- Node: 22.18.0
- npm: 10.9.3
npmPackages:
- @rspack/core: 2.1.5 (REGRESSION; last good 2.0.1)
- @rsbuild/core: 2.1.4
- storybook-builder-rsbuild: 2.1.0 and 3.3.4 (both affected)
Details
Regression range
Last good @rspack/core 2.0.1; broken in 2.1.x, still broken in the latest 2.1.5 (no 2.2.x yet).
What happens
A large app's Storybook production build (rsbuild + storybook-builder-rsbuild, mode: production):
- @rspack/core 2.0.1 → ~9.7 GB peak RSS, succeeds
- @rspack/core 2.1.5 → RSS climbs monotonically to ~50 GB and is OOM-killed
Same source, same config, only the @rspack/core version differs. Memory climbs during the module-build phase (Compilation:build_module_graph), before optimization, at a steady ~0.5 GB/s with no plateau — a per-module accumulation / leak signature that frees only at process teardown.
Bisection
- A light story (tiny graph) builds at ~2 GB. A single heavy story (~7150 modules:
@metaos/hub-sdk, many @fluentui/*, @apollo/client, graphql, relay-runtime, @griffel/core, plus first-party packages) OOMs at ~49 GB. So it scales with real graph size and one heavy entry is enough.
- Effective cost is ≈3.7 MB peak RSS per module on 2.1.x vs ≈0.7 MB on 2.0.x (~5×), retained inside rspack core until the build ends.
Ruled OUT (none changed the ~49 GB OOM)
- Storybook builder: Storybook 9 builder 2.1.0 AND Storybook 10 builder 3.3.4 both OOM.
- Loader: the JS
swc-loader (via @swc/core, both async transform and transformSync) and the Rust builtin:swc-loader all OOM.
- SWC Wasm plugins (this build uses none).
experiments.parallelCodeSplitting: false.
optimization.minimize: false, concatenateModules: false, innerGraph/usedExports/providedExports/sideEffects: false, inlineConst/inlineExports: false.
- Largest single modules (js-tiktoken 5 MB,
@fluentui/react-icons chunks) — stubbing them did not change peak RSS.
resolve.extensionAlias / resolve.fallback.
⇒ The extra memory is retained inside @rspack/core 2.1.x core during build_module_graph, per module, independent of loader, optimizer pass, or config.
Profiling
RSPACK_PROFILE=ALL + an RSS timeline on a single heavy story:
- The entire RSS climb is inside
Compilation:build_module_graph.
- The dominant trace span by wall time is the per-module transform hook (
@1js/custom-swc-loader → @swc/core), but that is only the per-module hook, not the memory cause (forcing transformSync and swapping to builtin:swc-loader both still OOM).
- The prebuilt
@rspack/binding is stripped, so the exact Rust allocation site can't be resolved on my side — a memory profile from a debug build (guidance welcome: RSPACK_PROFILE? heaptrack?) should pinpoint it.
Note on a minimal repro
I could not distill a public minimal repro (see "Steps to reproduce"). 13+ synthetic graphs — including one built from real public deps (20k @fluentui/react-icons + @fluentui/react-components + @apollo/client + relay-runtime + lodash-es) — all build with 2.1.5 using ≤ the memory of 2.0.1. The blow-up only reproduces on the real (partly first-party) graph. Happy to share a private repro or the 454 MB RSPACK_PROFILE trace with maintainers.
Reproduce link
No response
Reproduce Steps
There is no public minimal repro yet — the regression only reproduces on a large real graph (see "Note on a minimal repro" above). The reproduction/measurement methodology on the real build:
- Take a large app whose Storybook build produces a big module graph (thousands of first-party + Fluent UI / Apollo / Relay / griffel modules reached through a lazy
import() hub).
- Build it in
mode: production with @rspack/core 2.0.1 and record peak RSS (e.g. /usr/bin/time -v) → ~9.7 GB, succeeds.
- Change only
@rspack/core to 2.1.5 (same rsbuild/storybook-builder-rsbuild, same config) and rebuild → RSS climbs monotonically (~0.5 GB/s, no plateau) to ~50 GB and is OOM-killed.
- Reduce to a single "heavy" story to confirm one entry (~7150 modules) is enough to OOM on 2.1.5 while a "light" story stays ~2 GB.
- Confirm it is core (not a loader/optimizer/config) by the ruled-out list above.
I can share a private reproduction repo and/or the RSPACK_PROFILE=ALL trace (454 MB) that shows the whole climb inside Compilation:build_module_graph. Guidance on capturing a Rust-core memory profile (heaptrack / a debug @rspack/binding) would let me pinpoint the exact allocation site.
System Info
System:
Binaries:
npmPackages:
Details
Regression range
Last good @rspack/core 2.0.1; broken in 2.1.x, still broken in the latest 2.1.5 (no 2.2.x yet).
What happens
A large app's Storybook production build (rsbuild + storybook-builder-rsbuild,
mode: production):Same source, same config, only the
@rspack/coreversion differs. Memory climbs during the module-build phase (Compilation:build_module_graph), before optimization, at a steady ~0.5 GB/s with no plateau — a per-module accumulation / leak signature that frees only at process teardown.Bisection
@metaos/hub-sdk, many@fluentui/*,@apollo/client,graphql,relay-runtime,@griffel/core, plus first-party packages) OOMs at ~49 GB. So it scales with real graph size and one heavy entry is enough.Ruled OUT (none changed the ~49 GB OOM)
swc-loader(via@swc/core, both asynctransformandtransformSync) and the Rustbuiltin:swc-loaderall OOM.experiments.parallelCodeSplitting: false.optimization.minimize: false,concatenateModules: false,innerGraph/usedExports/providedExports/sideEffects: false,inlineConst/inlineExports: false.@fluentui/react-iconschunks) — stubbing them did not change peak RSS.resolve.extensionAlias/resolve.fallback.⇒ The extra memory is retained inside
@rspack/core2.1.x core duringbuild_module_graph, per module, independent of loader, optimizer pass, or config.Profiling
RSPACK_PROFILE=ALL+ an RSS timeline on a single heavy story:Compilation:build_module_graph.@1js/custom-swc-loader→@swc/core), but that is only the per-module hook, not the memory cause (forcingtransformSyncand swapping tobuiltin:swc-loaderboth still OOM).@rspack/bindingis stripped, so the exact Rust allocation site can't be resolved on my side — a memory profile from a debug build (guidance welcome:RSPACK_PROFILE? heaptrack?) should pinpoint it.Note on a minimal repro
I could not distill a public minimal repro (see "Steps to reproduce"). 13+ synthetic graphs — including one built from real public deps (20k
@fluentui/react-icons+@fluentui/react-components+@apollo/client+relay-runtime+lodash-es) — all build with 2.1.5 using ≤ the memory of 2.0.1. The blow-up only reproduces on the real (partly first-party) graph. Happy to share a private repro or the 454 MBRSPACK_PROFILEtrace with maintainers.Reproduce link
No response
Reproduce Steps
There is no public minimal repro yet — the regression only reproduces on a large real graph (see "Note on a minimal repro" above). The reproduction/measurement methodology on the real build:
import()hub).mode: productionwith@rspack/core 2.0.1and record peak RSS (e.g./usr/bin/time -v) → ~9.7 GB, succeeds.@rspack/coreto2.1.5(same rsbuild/storybook-builder-rsbuild, same config) and rebuild → RSS climbs monotonically (~0.5 GB/s, no plateau) to ~50 GB and is OOM-killed.I can share a private reproduction repo and/or the
RSPACK_PROFILE=ALLtrace (454 MB) that shows the whole climb insideCompilation:build_module_graph. Guidance on capturing a Rust-core memory profile (heaptrack / a debug @rspack/binding) would let me pinpoint the exact allocation site.