Memory
Rspack supports capturing memory snapshots during builds and HMR updates. When you report a memory issue, include these files to help maintainers investigate.
For users
Enable profiling
Use a debug or profiling package at this version or later (standard release packages do not include allocative support). Snapshot collection is off by default. To enable it, set RSPACK_ALLOCATIVE_DIR to an output directory when running your project.
Direct Rspack users
If your project depends on @rspack/core directly, replace it with the debug package at the same version. For example, change 2.3.0 to npm:@rspack-debug/[email protected]:
Keep the dependency in its original section (dependencies or devDependencies), then run pnpm install.
Users of frameworks such as Rsbuild
If your project uses Rspack indirectly through a framework such as Rsbuild, add a package manager override for @rspack/core. For pnpm, add this configuration to package.json:
Use the same version as the framework's resolved @rspack/core dependency (2.3.0 in this example), then run pnpm install. See Debugging for more about diagnostic package overrides.
For either approach, you can use a profiling build instead of the debug package. Set RSPACK_ALLOCATIVE_DIR when running your project's original build or dev command. Leave it unset to skip snapshot collection. If no suitable package is available, see Build a local binding to build from source.
Capture memory snapshots
Capture a build
Run the project's original build command with an absolute output directory:
Verify that the build, its configuration, and its plugins all load the intended diagnostic package. For Rspack-integrated frameworks, keep the framework's normal build command and use a compatible diagnostic package override.
After the initial build completes, the output directory contains:
Use a fresh directory for each process. Snapshot numbering is shared across compilers within a process and resets in a new process. Reusing a directory between processes can overwrite files.
Capture HMR updates
Set the same output variable when starting the dev server:
Edit a source file and wait for each rebuild to finish. A single compiler with three rebuilds produces four byte snapshots:
Each snapshot also has matching counts, metadata, and warnings files. Watch-mode builds using the same package can also collect snapshots via RSPACK_ALLOCATIVE_DIR.
Keep the project's build mode and sourcemap settings while reproducing the issue, and record the edits made for each HMR update.
Attach data to an issue report
After the build or the intended HMR updates have completed, compress the entire output directory and attach the archive to your issue report. Include all four file types for every snapshot:
For example, archive the build capture directory:
For an HMR issue, archive the complete sequence from the initial build through the last relevant rebuild, including all matching files for each snapshot. Keep the original filenames so maintainers can match the snapshots and sidecars.
Include this context in the issue report:
- The Rspack and diagnostic package versions, Node.js version, and operating system.
- The command, configuration, build mode, and sourcemap setting used for the capture.
- A reproduction project or reproduction steps; for HMR, include the edits and their order.
- The observed memory issue, when it occurs, and the build logs. If no snapshots were produced, report that along with the command and logs.
The developer section explains how to inspect the data.
For Rspack developers
Use the allocative skill
The Rspack repository includes the rspack-allocative skill. The skill prepares build artifacts, runs the workload, and generates memory snapshots and count reports.
Default benchmark projects
The skill uses the repository's built-in benchmark projects by default and prepares the fixtures as needed. With no project or test case specified, it captures the Three.js 10x development build:
You can also name a preset workload, such as threejs-10x-production-sourcemap for a production build with sourcemaps.
External projects
To capture an external project, specify its directory and build mode:
--project-dir is an argument in the skill request, interpreted by the agent — it is not a Rspack CLI option. Relative paths resolve from the agent's initial working directory; quote paths that contain spaces. You can also describe the project directory in natural language. The project directory selects the workload; the Rspack checkout selects the local binding and JavaScript packages. If a project has several configurations, specify the configuration file and build mode in the request.
Rspack test cases
The skill also supports collecting data directly from Rspack test cases. Specify the case directory, for example:
For example, using the hotCases/source-map/disable case produces these memory snapshot files:
Each snapshot also has matching .counts.json, .metadata.json, and .warnings.txt files.
You can use a separate output directory for each run to avoid overwriting data. The skill reports the selected project, build method, capture phase, output paths, and coverage limits. Inspect the snapshots in Speedscope as described in View snapshots.
View snapshots
A snapshot traces ownership paths from the compiler and registered global roots. Its weights are bytes, not execution time or allocation events.
Open Speedscope and drag in a .allocative file. Use search and zoom to find a data structure, and select Left Heavy to explore the largest ownership paths.
Wider frames represent more bytes. The paths describe ownership, not allocation call stacks. The folded format does not carry a unit, so treat the weights as bytes even if the viewer displays a different label. Time Order is not a timeline for these snapshots.
Read the matching .metadata.json and .warnings.txt before interpreting the total. Metadata includes the represented byte total, shared-ownership policy, and global string arena usage. Warnings identify inaccessible nested allocations and other coverage gaps.
Read entry counts
The .counts.json sidecar records module and dependency entries in the current compilation's module graph, grouped by type. These are collection cardinalities — not a process-wide object count or allocation count. An empty graph produces explicit zero-valued module and dependency populations.
Do not derive counts by dividing byte weights by a type's size or by counting lines in a .allocative file. A collection can reserve more storage than its length, and multiple references can share one allocation.
The skill automatically prepares summary.json, counts.csv, and counts.folded when count data is available. Open a nonempty counts.folded file in Speedscope to explore entry counts rather than bytes. Zero-valued populations remain in the table and summary but produce no chart frames.
Interpret the results
Compare matching snapshots from the same phase and with the same workload. For example, if module and dependency counts stay stable during repeated HMR updates while represented bytes grow, inspect which ownership paths retain more data. This observation alone does not establish a memory leak.
Limitation:
- Snapshots do not measure RSS, peak memory, or cumulative allocations.
- JavaScript and V8 heap objects, callback captures, some external state, allocator metadata, and private container overhead are not fully represented. Nonblocking locks and unsupported nested types can also limit coverage.
Advanced
How memory collection works
Rspack maintains a fork of Buck2's allocative in crates/rspack_allocative. The fork uses Rust's compile-time reflection and a compiler driver to collect memory data automatically in most cases, reducing the need for manual Allocative implementations.
Borrowed references do not imply ownership; raw pointers and unsupported values are treated as opaque. Shared allocations are counted once under the first encountered owner. These policies avoid double-counting shared payloads, but inaccessible state still limits coverage.
When manual Allocative is needed. Ordinary structs and most enums are instrumented automatically, but some cases require explicit adapters or annotations:
- Third-party types require an
Allocativeimplementation inrspack_allocative. - Unions aren't supported by the derive macro — implement
Allocativeby hand. - Custom ownership where memory layout doesn't match actual ownership, such as arena-allocated data, borrowed buffers, or shared pointers. Write a manual implementation to express the right traversal.
- Opaque or unsupported values like raw pointers, callback captures, and V8 heap objects. Mark these fields with
#[allocative(skip)]to exclude them. - Incorrect generic bounds from the default derive. Use
#[allocative(bound = "...")]to supply your own constraints. - Enum reflection edge cases. The compiler driver's enum reflection needs
Self: 'staticand skips enums with lifetime parameters, const generics, or non-literal array types. These fall back to typed traversal and need explicit adapters.
The capture flow is:
The capture points are in compiler/mod.rs and compiler/rebuild.rs. snapshot_allocative visits the roots and writes the files. This measures the represented memory at that point, with the limits described in Interpret the results.
Build a local binding
After setting up the development prerequisites, run these commands from the Rspack repository root:
The debug build includes allocative support by default; snapshot collection is still off by default. The build:binding:debug command uses the release-debug Cargo profile. Standard release builds do not include allocative support. The profiling build also includes this support by default:
To include allocative support in the development build (build:binding:dev) or another binding build profile, set ALLOCATIVE=1 when building:
Setting ALLOCATIVE=1 at runtime alone does not add instrumentation to an existing binding. Debug and profiling builds do not collect snapshots unless RSPACK_ALLOCATIVE_DIR is set.
Profile a local build or test
Run the built CLI from the target project's working directory:
Tests using the local binding can also collect snapshots via RSPACK_ALLOCATIVE_DIR. Each build or rebuild produces a snapshot automatically; the test framework does not need a separate capture integration. After building the binding and JavaScript packages, run a focused HMR case:
The literal double quotes in the positional argument select the exact HotNode.test.mjs runner; -t selects the fixture. Use one worker and a fresh output directory. For other runners or concurrent processes, give each process its own directory to avoid overwriting snapshots. See Testing for the repository's test conventions.
Prepare count reports
For manually captured snapshots, run the report helper with a new output directory:
It discovers matching sidecars and generates the summary and count reports described in Read entry counts. The skill runs this step automatically.

