For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt, and this page is available as Markdown at /config/test/pool.md.
close
  • English
  • pool

    • Type:
    export type RstestPoolType = 'forks' | 'threads' | 'vmForks' | 'vmThreads';
    
    export type RstestPoolOptions = {
      /** Worker pool used to run tests. */
      type?: RstestPoolType;
      /** Maximum number or percentage of workers to run tests in. */
      maxWorkers?: number | string;
      /**
       * Memory threshold used to recycle a worker after it finishes a test file.
       * This is a worker-recycling threshold, not a hard process RSS limit.
       * Values in `(0, 1]` are fractions of system memory; larger numbers are bytes,
       * and strings may use `%`, `MB`, `MiB`, `GB`, or `GiB` suffixes.
       * Uses RSS for `forks` with `isolate: false`, and V8 heap for VM pools.
       * Ignored by `threads` and isolated `forks`.
       * @default undefined (`system memory / maxWorkers` for VM pools)
       */
      memoryLimit?: number | string;
      /** Pass additional Node.js arguments to workers. */
      execArgv?: string[];
    };
    
    export type RstestConfig = {
      /** Worker pool used to run tests. */
      pool?: RstestPoolType | RstestPoolOptions;
    };
    • Default:
    const defaultPool = {
      type: 'forks',
      // maxWorkers is computed from CPU count and command mode
    };
    • 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:

    ScenarioPool to tryCheck before switching
    Short test files spend a large share of their time starting workersthreadsTests and dependencies support worker-thread API and native-addon restrictions
    Many files repeatedly start workers and load and compile dependenciesvmThreadsTests support worker-thread and cross-realm restrictions
    Worker reuse is desirable, but you also need process APIs or easier memory-pressure controlvmForksTests tolerate process state persisting within a worker and cross-realm restrictions

    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.

    CLI
    rstest.config.ts
    npx rstest --pool forks

    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.title cannot be changed.
    • OS signals are not delivered through process.on(), and process.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.

    CLI
    rstest.config.ts
    npx rstest --pool threads

    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.

    CLI
    rstest.config.ts
    npx rstest --pool vmForks

    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.

    CLI
    rstest.config.ts
    npx rstest --pool vmThreads --pool.memoryLimit 256MB

    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.

    rstest.config.ts
    import { defineConfig } from '@rstest/core';
    
    export default defineConfig({
      pool: {
        maxWorkers: 1,
      },
    });

    You can also pass the value from the CLI:

    npx rstest --pool.maxWorkers 1

    Common values:

    • 1: run test files one at a time. This is the Rstest equivalent of Vitest's fileParallelism: false and 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 than 1 are bytes.
    • A string: supports %, KB, KiB, MB, MiB, GB, and GiB, 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:

    rstest.config.ts
    import { defineConfig } from '@rstest/core';
    
    export default defineConfig({
      pool: {
        type: 'vmThreads',
        maxWorkers: 4,
        memoryLimit: '256MB',
      },
    });

    You can also set it from the CLI:

    npx rstest --pool vmThreads --pool.memoryLimit 256MB

    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:

    rstest.config.ts
    import { defineConfig } from '@rstest/core';
    
    export default defineConfig({
      pool: {
        execArgv: ['--conditions=development'],
      },
    });

    When debugging, combine it with maxWorkers: 1 to run files one at a time and make execution easier to follow:

    rstest.config.ts
    import { defineConfig } from '@rstest/core';
    
    export default defineConfig({
      pool: {
        maxWorkers: 1,
        execArgv: ['--inspect-brk'],
      },
    });

    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:

    Loading pathSupport and limits
    Test/setup bundles and external JavaScriptExecute in the file VM, including static and dynamic imports. Setup and evaluated module state are recreated per file.
    CommonJS named exportsStatically detected own exports, including non-enumerable properties and getters, are read from the original module.exports receiver. They are snapshots, not live bindings; interopDefault still applies.
    JSON, WebAssembly, and data: URLsJSON ESM imports require type: 'json'. Asynchronous WebAssembly and JavaScript, JSON, and base64 WebAssembly data: URLs are supported. Synchronous Wasm require() is unsupported.
    Synchronous require(esm)Requires Node.js 24.9+ and VM graph support. Async graphs throw ERR_REQUIRE_ASYNC_MODULE; older VM implementations reject ESM require with ERR_REQUIRE_ESM.
    Native addonsDirect CommonJS require() delegates to Node.js. VM ESM imports of .node files are unsupported, and addon state is not VM-isolated.
    CommonJS resolutionNode.js require.resolve() selects paths and export conditions. Rstest does not choose a fallback entry if the selected entry cannot run in the VM.
    Module._cacheExposes the file's require.cache for inspecting and deleting CommonJS/JSON entries. Replacing or deleting _cache itself is unsupported. Synchronous require(esm) uses the VM ESM cache without CommonJS cache records or module.children links.