Environment variables
Every environment variable Pyro reads, by the component that reads it. The browser binary reads the PYRO_* serve, browser and tuning variables and JSC_*; the SDK and the runners read PYRO_BIN, PYRO_WS, the Playwright drop-in's PYRO_* variables, NO_COLOR and NODE_ENV. Releases up to 0.0.33 (@povio/lightning-panda) read the same variables as LIGHTNINGPANDA_* (browser, LIGHTNINGPANDA_BIN, LIGHTNINGPANDA_WS) and LP_* (Playwright drop-in); see Renamed from Lightningpanda. Variables marked diagnostic or tuning exist to measure or compare behaviour. They are stable enough to use, but you should not need them.
Quick reference
| Variable | Read by | Default | Purpose |
|---|---|---|---|
PYRO_BIN | SDK, CLI, runners | bundled binary | Browser binary to run |
PYRO_WS | Playwright drop-in | launch one | Connect to a running server |
PYRO_CONFIG | Playwright drop-in | pyro.config.*, playwright.config.* | Config file |
PLAYWRIGHT_CONFIG | Playwright drop-in | Fallback for PYRO_CONFIG | |
PYRO_PROJECT | Playwright drop-in | first project | Project to use |
PYRO_RETRIES | Playwright drop-in | config | Retries |
PYRO_TIMEOUT | Playwright drop-in | config | Test timeout, ms |
PYRO_UPDATE_SNAPSHOTS | SDK, Playwright drop-in, e2e | unset | Write screenshot baselines |
PYRO_CONCURRENT | Playwright drop-in | unset | Run parallel describes concurrently in a worker |
NO_COLOR | run, e2e reporters | unset | Disable colors |
PYRO_LOCAL_STORAGE | serve | --local-storage | |
PYRO_STATIC | serve | --static entries | |
PYRO_PREPARE | serve | --prepare URLs | |
PYRO_PREPARE_REFILL | serve | quiet | --prepare-refill |
PYRO_FORK | serve | off | --fork |
PYRO_FORK_SPARES | serve --fork | 2 | Forks kept waiting |
PYRO_FORK_PRECOMPILE | serve --fork | modules | Precompile static module scripts |
PYRO_SPARE_ENGINE | serve | on with --prepare | --spare-engine |
PYRO_ENGINE_REUSE | serve (newer than 0.0.33) | on | --engine-reuse |
PYRO_RENDER_PREWARM | serve | on with --prepare | --render-prewarm |
PYRO_HYPHEN_DIGIT_BREAKS | serve | off | --hyphen-digit-breaks |
PYRO_PARENT_PID | serve | set by launch() | --parent-pid |
PYRO_VIRTUAL_TIME | browser | off | Jump the clock to the next timer while a run waits |
PYRO_FILE_URLS | browser | on | Serve file: URLs |
PYRO_SHARED_ASSET_CACHE_MB | browser | off | Cross-context cache of public static assets |
PYRO_PDF_SHADOWS | PDF renderer | on | Draw blurred box shadows in PDFs |
JSC_* | JavaScriptCore | see below | Engine options |
The memory, tuning and diagnostic variables are listed in their own sections below.
SDK and CLI
PYRO_BIN
Path to a pyro binary. The pyro npm command, Pyro.launch() (when no bin option is passed), the Playwright drop-in and the e2e runner use it in place of the bundled binary. Use it for a binary you built yourself, or on a platform with no bundled one. Default: a pyro next to the package (the release-archive layout), else native/<platform>-<arch>/pyro in the package.
PYRO_BIN=$HOME/src/pyro/target/release/pyro bun testPYRO_WS
The WebSocket endpoint of a running pyro serve (for example ws://127.0.0.1:9222/). The Playwright drop-in (@povio/pyro/wright and pyro run) connects to it instead of launching a browser per worker, unless the config's pyro.wsEndpoint option is set. Pyro.connect() does not read it, but scripts often pass it: Pyro.connect(process.env.PYRO_WS!). See One server, many workers.
PYRO_CONFIG
Path of the Playwright-style config file the drop-in loads (absolute, or relative to the working directory). pyro run -c <file> sets it for its workers. Fallback: PLAYWRIGHT_CONFIG, then pyro.config.{ts,mts,mjs,js}, then playwright.config.{ts,mts,mjs,js} in the working directory. Set it when you run a file with plain bun test.
PYRO_PROJECT
Name of the config project whose settings apply. Default: the first project. An unknown name throws pyro: no project named "<name>" in <config file>. When it is unset and the config has several projects, a file takes the project whose testDir/testMatch include it.
PYRO_RETRIES
Retries of a failing test, overriding the config and project values. pyro run --retries <n> sets it.
PYRO_TIMEOUT
Test timeout in ms for every project, overriding the config. pyro run --timeout <ms> sets it.
PYRO_UPDATE_SNAPSHOTS
Write screenshot baselines instead of comparing.
| Reader | Values |
|---|---|
SDK matchScreenshot steps (updateMode()) | 1, true, all or changed turn update mode on. Passing --update-snapshots or -u to the process (bun test -u) does the same. |
Playwright drop-in toHaveScreenshot / toMatchSnapshot | all, changed, missing, none (Playwright's updateSnapshots). pyro run -u [mode] sets it (default changed). |
pyro e2e -u | Sets it to 1. |
NO_COLOR
Any value turns off ANSI colors in the pyro run and pyro e2e console output. Colors are also off when stdout is not a TTY.
NODE_ENV
pyro e2e sets it to test if it is unset, as bun test does.
Set by the runners
pyro run passes these to its bun test workers. They are internal: do not set them yourself.
PYRO_WORKER, PYRO_WORKERS, PYRO_WORKER_INDEX, PYRO_RESULTS, PYRO_FILE_PROJECTS, PYRO_FILE_OWNERS, PYRO_FULLY_PARALLEL, PYRO_GREP, PYRO_GREP_INVERT and PYRO_LIST.
PYRO_CONCURRENT
1 makes the Playwright drop-in run the tests of a mode: 'parallel' describe concurrently inside one worker. By default a file's tests run one after another in their worker, since they may share module state that hooks set. Experimental.
serve
Each variable is the default for its flag, and the flag wins. Switches take on/off, 1/0 or true/false. A value that does not parse is ignored. Full descriptions are in serve options.
PYRO_LOCAL_STORAGE
Path of the JSON file for --local-storage. Empty means unset.
PYRO_STATIC
--static entries ORIGIN=DIR, separated by ;. --static flags add to them. Malformed entries are skipped.
PYRO_STATIC='http://app.test=./dist;http://cdn.test=./public'PYRO_PREPARE
--prepare URLs, separated by ;. --prepare flags add to them.
PYRO_PREPARE_REFILL
after-close means --prepare-refill after-close. Any other value means quiet.
PYRO_FORK
1 means --fork. Other values are ignored.
PYRO_FORK_SPARES
How many forked processes each fork-mode template keeps waiting for connections. Default 2. Raise it when many connections open at once.
PYRO_FORK_PRECOMPILE
What the root fork-mode template does with the module scripts of the --static roots before its first page. Every fork then loads them already compiled. Tuning.
| Value | Effect |
|---|---|
modules (default) | Each module is parsed and its top-level code compiled. Functions compile at their first call, in the calling process. |
functions | The code of every function is compiled too. This saves a little CPU per page but costs more memory and page faults. |
off, 0 | Nothing is precompiled. |
PYRO_SPARE_ENGINE
on/off for --spare-engine.
PYRO_ENGINE_REUSE
on, off, thread or always (also 1/0, true/false) for --engine-reuse. Newer than 0.0.33: since the first @povio/pyro release.
PYRO_RENDER_PREWARM
on/off for --render-prewarm.
PYRO_HYPHEN_DIGIT_BREAKS
on/off for --hyphen-digit-breaks. Default off.
PYRO_PARENT_PID
The PID for --parent-pid. Pyro.launch() sets it to its own PID in the server's environment. A fork-mode template removes it from its own environment, so the template ends with its server instead.
Browser behaviour
These are read by the browser in any mode (serve, fetch, eval).
PYRO_VIRTUAL_TIME
1 turns on virtual time. While an Pyro.run waits and its page has nothing left but timers (no task, request or navigation), the clock jumps to the next timer instead of sleeping until it is due. A debounce or a delayed save then costs no wall time. The jump applies to the whole browser thread, so it is meant for fork mode (one page per process). Time never goes back. Default: off.
PYRO_FILE_URLS
0 turns off file: URLs. They then fail with net::ERR_UNKNOWN_URL_SCHEME. Default: on, so navigations to file: and the subresources of file: documents read the local filesystem, as Chrome does.
PYRO_SHARED_ASSET_CACHE_MB
A positive integer turns on a process-wide cache of public static assets shared across browser contexts, with that many MiB (each entry up to 16 MiB). It is read once per process. Default: off, so every context keeps its own HTTP cache.
PYRO_PDF_SHADOWS
0 skips blurred outset box-shadows when printing to PDF. Default: drawn.
Memory and tuning
Tuning. These were added to compare behaviours in benchmarks. The defaults are the measured best choice.
| Variable | Default | Effect of setting it |
|---|---|---|
PYRO_RELEASE_ON_CLOSE | on | 0: closing a page no longer releases its memory (collection and free pages returned). The memory waits for the engine's next collection |
PYRO_RELEASE_GROWTH | 32:25 | <MB>[:<percent>]: how far the footprint must grow past its low point before a close collects. 0 collects on every close |
PYRO_RELEASE_PUT_OFF | 1 | How many closes past the gate may leave their collection to an idle moment before one collects at once |
PYRO_DECOMMIT | patched behaviour | madvise: keep JavaScriptCore's stock page release. By default, freed pages leave the resident set at once |
PYRO_HEAP_ARENA (macOS, newer than 0.0.33) | on | 0: use mimalloc's own arenas for the Rust heap instead of one reserved range whose freed pages leave the resident set at once |
PYRO_FORK_FAST_EXIT | on | 0: a forked connection process tears down as a shared process does instead of exiting at once |
PYRO_STATIC_DIRECT | on | 0: --static hits go through the I/O thread instead of being answered on the browser thread |
Diagnostics
Diagnostic. Output formats may change between releases.
| Variable | Output |
|---|---|
PYRO_FORK_STATS=<file> | JSON lines appended to <file>, one per fork, reaped child, child life step and precompile in serve --fork |
PYRO_ENGINE_REUSE_LOG=1 (newer than 0.0.33) | One stderr line per connection end (pyro: engine reuse: …): what became of its engine |
PYRO_TRACE_MODULES=1 | One stderr line per step of every ES module load |
PYRO_FLOW_STATS=1 | Layout flow statistics |
PYRO_GEOMETRY_PROFILE (any value) | Time spent in layout syncs, whole-document reads and box reads, printed to stderr every 250 syncs |
PYRO_GEOMETRY_DEBUG (any value) | Describes elements whose layout box is empty |
PYRO_MIRROR_FULL_LAYOUT (any value) | The render mirror relays out the whole document on every render instead of incrementally (tells a layout difference from a mirroring one) |
PYRO_MIRRORDBG (any value) | Logs mirror nodes that arrive with unknown children |
PYRO_RUN_STEP_TRACE=1 | Per-step trace records of each Pyro.run (not Pyro.act/Pyro.expect) |
PYRO_POINTER_WAIT_DIAGNOSTICS (any value) | Pointer-action timeout messages include why the action was not ready |
JavaScriptCore options
JavaScriptCore reads JSC_<option> variables once, when it creates its first VM. Pyro sets some defaults for itself unless the variable is already set in the environment:
| Variable | Pyro's default | Why |
|---|---|---|
JSC_usePollingTraps | true | The watchdog (--timeout-ms, termination) must reach JIT-compiled loops |
JSC_heapGrowthMaxIncrease | 1 (3 in fork-mode forks) | Lower heap peaks. In forks, fewer collections for short-lived processes |
JSC_smallHeapSize | 4194304 | 4 MB between collections instead of 1 MB. 1048576 restores the old trade-off |
JSC_useMachForExceptions | false (processes that fork) | Mach exception ports do not survive fork() |
JSC_useDFGJIT | false in fork-mode forks | DFG/FTL compilation rarely pays off in a short connection. JSC_useDFGJIT=true restores the default tiers |
JSC_jitMemoryReservationSize | 33554432 in fork-mode forks | 32 MB JIT pool instead of 512 MB, so fork() is faster on macOS |
Any other JSC_* option reaches JavaScriptCore unchanged. Options you set this way are outside what Pyro tests.
Build-time variables
Read when building Pyro from source, not by a built binary: PYRO_JSC=system (link the system JavaScriptCore framework instead of the patched build), PYRO_JSC_DIR=<dir> (link the patched JavaScriptCore in <dir>/lib) and PYRO_JSC_CACHE (the artifact root scripts/jsc/build.sh writes to). PYRO_HEAP_PROFILE and PYRO_HEAP_PROFILE_INTERVAL only work in binaries built with the heap-profile feature, which release builds are not.