pool
- Type:
- Default:
- CLI:
--pool <type>,--pool.type <type>,--pool.maxWorkers <value>,--pool.memoryLimit <limit>,--pool.execArgv <arg>
Configure the worker pool Rstest uses to run tests, including isolation, concurrency, and memory recycling thresholds.
Choose a pool type
Start with the default forks pool. It introduces the fewest execution restrictions of the four pools and offers broader compatibility with Node.js APIs and native addons. The default isolate: true also gives each test file a separate process, preventing process-level state from persisting between files and containing native crashes within the child process.
If performance does not meet your expectations, first identify where the time is spent. The rstest-debugging skill can help; see Profiling for installation and analysis guidance. If worker startup or module loading is the bottleneck, consider these options:
VM pools reuse workers and compilation resources, which can benefit suites with many files or large setup dependencies. Setup files, test environment creation, and module evaluation still run for every file, however. Switching to a VM pool will not eliminate database initialization or network requests performed in setup. Use your project's runtime and memory measurements to make the final choice.
Pool types
forks and threads run tests in child processes and worker threads, respectively. vmForks and vmThreads reuse those workers while creating a fresh vm.Context for each file.
All pools serialize environment options before sending them to workers, so functions are not supported in those options. See testEnvironment.options for the requirements.
forks
Creates Node.js child processes with child_process.fork. Each worker has separate process memory and process-level state. By default, every file gets a new process; with isolate: false, multiple files can reuse the same child process.
With the default isolation setting, each file incurs process startup and initialization costs.
threads
Runs tests through node:worker_threads. Each worker has its own V8 isolate and heap, but all threads share one operating-system process. RSS therefore measures memory usage across the entire process.
Threads generally start faster than child processes, but have some Node.js API restrictions. The following differences apply to both threads and vmThreads:
process.chdir(),process.abort(), and methods that change user or group IDs are unavailable;process.titlecannot be changed.- OS signals are not delivered through
process.on(), andprocess.exit()terminates only the worker thread. - Native addons must support use in worker threads. A native crash can affect the entire process.
See the Node.js Worker documentation for the full list of differences.
vmForks
Reuses child processes and creates a fresh vm.Context for each test file, reducing repeated process startup. Process APIs such as process.chdir() remain available, but files in the same child process can share process-level state.
vmThreads
Reuses worker threads and creates a fresh vm.Context for each test file, reducing repeated thread startup. It provides the same VM isolation as vmForks, with the worker-thread restrictions described above.
For the isolation scope and compatibility requirements of both VM pools, see VM pool behavior at the end of this page.
Configure worker concurrency and memory
pool.maxWorkers
pool.maxWorkers controls how many test files run at the same time. Lower it to reduce resource conflicts when tests share a database, port, or fixture directory.
The default is computed from the CPU count and the command mode. You can provide a positive integer or a percentage of the available CPU count.
You can also pass the value from the CLI:
Common values:
1: run test files one at a time. This is the Rstest equivalent of Vitest'sfileParallelism: falseand Jest's--runInBand.50%: keep parallelism proportional to the available CPU count, which is useful on CI machines with shared capacity.- A fixed number such as
4: run at most 4 workers, regardless of the machine's CPU count.
maxWorkers is about file-level parallelism. It does not limit test.concurrent cases inside a single test file — use maxConcurrency for that.
pool.memoryLimit
As a VM worker runs successive files, its memory usage can grow. pool.memoryLimit controls when to recycle it: after each file, Rstest checks the worker's V8 heapUsed. If it reaches the threshold, Rstest recycles the worker and runs subsequent files in a new one.
For vmForks and vmThreads, the default threshold is system memory / maxWorkers.
For forks with isolate: false, an explicit memoryLimit checks the child process's RSS instead. There is no limit by default. With isolate: true, fork workers are already discarded after each file, so this option is ignored. Ordinary threads also ignore it because RSS measures the entire process, not an individual worker thread.
To set a threshold, use one of these formats:
- A number: values in
(0, 1]are fractions of system memory; values greater than1are bytes. - A string: supports
%,KB,KiB,MB,MiB,GB, andGiB, such as'25%'or'256MB'.
For example, this configuration runs up to 4 VM workers. After each file, a worker whose heap usage reaches 256MB is recycled:
You can also set it from the CLI:
memoryLimit triggers recycling only between files. It is not a hard process RSS limit and cannot guarantee that a run avoids OOM.
It also bounds each VM worker's shared cache of immutable assets, external source, resolution results, and compilation data to the smaller of 64 MiB and one quarter of memoryLimit. Lowering the threshold can shrink this cache and increase loading and compilation work.
Separately, vmForks can use each child process's RSS to defer worker creation under memory pressure. This makes memory pressure easier to control than with the shared process RSS of vmThreads. This scheduling mechanism operates independently of memoryLimit; child processes still have additional overhead, so actual memory usage is not necessarily lower.
Pass Node.js flags to workers
Use pool.execArgv to pass Node.js startup flags to workers. For example, this configuration enables the development condition:
When debugging, combine it with maxWorkers: 1 to run files one at a time and make execution easier to follow:
VM pool behavior
These restrictions apply to both vmForks and vmThreads.
Isolation and cleanup
Each file gets a fresh VM context, module graph, and test environment. Worker-scoped fixtures are also created and cleaned up per file, regardless of isolate. Workers are reused, however, so state outside the VM, such as process.env and native-addon state, may persist across files.
Tests must still await or cancel asynchronous work before the file finishes. Teardown clears timers managed by Rstest, but does not cancel arbitrary Promise chains, native I/O, or background tasks.
Pending wrapped node:timers/promises and promisified timeout/immediate operations are cancelled with AbortError. Cancellation may run user catch or finally handlers, so teardown does not guarantee that no user code runs afterward.
Cross-realm assertions
Values from Node.js, workers, or DOM environments may use different constructors and fail instanceof checks in the current VM. Use await and content assertions, and check an error's name, code, or message.
Module loading
Test and setup bundles, external JavaScript ESM, and CommonJS can run in the VM. Custom Node.js loaders and external TypeScript execution are unsupported; compile or bundle those files first.
Synchronous require(esm) requires Node.js 24.9+, VM graph support, and a dependency graph without top-level await. Otherwise, use dynamic import(). Native addons can only be loaded through direct CommonJS require(), and their state is outside VM isolation.
Module loading compatibility
VM loading differs from the native Node.js loader in the following ways: