# nodejs/node — codebase unpack

> Canonical page: https://codevetter.com/unpack/node

This is a deterministic Repo Unpack scan of nodejs/node — a structural map, not a review, security audit, or maintainer-endorsed description.

- Scanned commit: 976a36a5b6ce737c9e695f6cde8e141427f13737 (2026-09-22)
- Last upstream commit: 2026-09-22, Version 26.10.0 (Current)
- Generated by codevetter 1.12.0 on 2026-09-22
- 3999 files scanned · 43.3 MB

## Languages

- JavaScript: 23278 files
- C: 10589 files
- C++: 4546 files
- HTML: 1519 files
- Rust: 973 files
- JSON: 794 files
- Markdown: 682 files
- Python: 570 files

## Repository structure

- test/ — 863 files
- deps/ — 863 files
- benchmark/ — 637 files
- src/ — 495 files
- lib/ — 429 files
- tools/ — 391 files
- doc/ — 162 files
- .github/ — 60 files

Probable source entrypoint: `src/` (inferred from the tree, not upstream docs)

## Package

- pyproject.toml: null — 0 declared dependencies

## Structural health signals

Average score 5.4/10 across 96 files; 94 hotspots. These are deterministic review leads, not proof of a bug.

## Recent history

- 976a36a5b6ce (2026-09-20) 2026-09-22, Version 26.10.0 (Current)
- d4120cbcc617 (2026-09-22) tools: update nixpkgs-unstable to 79b35bf0bda5cd110f856aa5b5b2c5ba446
- 44ff2db1e671 (2026-09-22) typings: share AsyncWrap and HandleWrap types
- 1eacebb14308 (2026-09-22) watch: strip watch flags from NODE_OPTIONS in child process
- dd9f4dac3296 (2026-09-21) sqlite: add virtual table support via createModule()

## Overview

This is the Node.js runtime itself at v26.10.0 — a C++/V8 host (src/, ~495 files) wrapping a JavaScript standard library (lib/, ~429 files) that is compiled into a V8 startup snapshot at build time. Beyond upstream-familiar surface, this tree carries several large experimental subsystems wired through the same plumbing: a `node:vfs` virtual file system that intercepts `node:fs` and the module loaders at reserved mount points under `os.devNull/vfs/<id>`, a `node:ffi` libffi-backed foreign function interface gated by a `kFFI` permission scope, a `node:dtls` endpoint/session stack, a `node --experimental-bench` benchmark runner mirroring the test runner, and a vendored Rust crate set (`deps/crates`, temporal_rs + ICU) linked as a staticlib. The audience is Node core collaborators; the distinctive engineering property is that every new capability is a triple — a CLI option in `src/node_options.cc`, a `setupX()` in `pre_execution.js` that calls `BuiltinModule.allowRequireByUsers()`, and an internal binding registered in `src/node_binding.h`.

## System map

Execution begins in `src/node_main.cc` (`main`/`wmain`) which calls `node::Start`, which after SEA argv fixup loads the V8 startup snapshot and runs a `NodeMainInstance`. C++ then picks exactly one main script from `lib/internal/main/` via a linear dispatch in `src/node.cc`; that script calls into `lib/internal/process/pre_execution.js` to configure the realm before user code. The JS layer talks to C++ only through `internalBinding()`, whose registry is the `NODE_BUILTIN_*_BINDINGS` macro list in `src/node_binding.h`. Build is GYP/Make (`configure.py` → `node.gyp` → `Makefile`) with a secondary GN path, plus Cargo for `deps/crates`. There is no deployment target in the usual sense: the artifact is the `node` binary, optionally repackaged as a single executable application by `src/node_sea.cc`.
- The process entrypoint is `main()` (POSIX) / `wmain()` (Windows, which UTF-8-converts wide argv and refuses pre-Windows-10 unless `NODE_SKIP_PLATFORM_CHECK=1`), both delegating to `node::Start`. — [src/node_main.cc#L34-100](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/node_main.cc#L34-L100)
- `node::Start` first runs `sea::FixupArgsForSEA` so a single-executable build can rewrite its own argv, then calls `StartInternal`, which branches to `sea::BuildSingleExecutable`/`WriteSingleExecutableBlob` or `GenerateAndWriteSnapshotData` before falling through to `LoadSnapshotData` + `NodeMainInstance::Run`. — [src/node.cc#L1690-1740](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/node.cc#L1690-L1740)
- C++ selects the JS main script by an ordered if-chain in `src/node.cc`: worker_thread → inspect → print_help → prof_process → eval_string → check_syntax → bench_runner → test_runner → watch_mode → run_main_module → repl → eval_stdin. Adding a new run mode means adding a branch here plus a file in `lib/internal/main/`. — [src/node.cc#L351-413](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/node.cc#L351-L413) [lib/internal/main](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/main)
- The JS↔C++ boundary is the `internalBinding()` registry declared by macro lists in `src/node_binding.h`; optional subsystems are compiled in conditionally — `quic` behind `HAVE_OPENSSL && OPENSSL_NO_QUIC != 1`, `dtls` behind `HAVE_OPENSSL && HAVE_DTLS`, `sqlite`/`webstorage` behind `HAVE_SQLITE`, `ffi` behind `HAVE_FFI`. — [src/node_binding.h#L28-81](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/node_binding.h#L28-L81)
- `lib/internal/bootstrap/node.js` is executed by `Realm::BootstrapRealm()` and is normally *not* run at startup — its resulting V8 heap is captured into the build-time snapshot by `SnapshotBuilder::Generate()`; `--no-node-snapshot` forces real execution. It must stay synchronous and must not read argv or env at top level. — [lib/internal/bootstrap/node.js#L1-48](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/bootstrap/node.js#L1-L48) [src/node_snapshotable.cc](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/node_snapshotable.cc)
- `prepareExecution()` in `pre_execution.js` is the single funnel every main script passes through; it patches the process object, runs ~25 `setupX()` initializers, calls `initializePermission()`, initializes the module loaders, and mounts the VFS before returning the resolved main entry. — [lib/internal/process/pre_execution.js#L109-200](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/process/pre_execution.js#L109-L200)
- The storage layer is threefold: the real file system via the `fs`/`fs_dir`/`glob` bindings, SQLite via `src/node_sqlite.cc` (which now exposes virtual tables through a `VirtualTableModule` wrapping `sqlite3_module`), and Web Storage via the `webstorage` binding gated on `--experimental-webstorage`. — [src/node_sqlite.cc#L1029-1060](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/node_sqlite.cc#L1029-L1060) [src/node_binding.h#L46-52](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/node_binding.h#L46-L52) [lib/internal/process/pre_execution.js#L570-575](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/process/pre_execution.js#L570-L575)
- External native dependencies are vendored under `deps/` (v8, uv, openssl, ada, llhttp, nghttp2, ngtcp2, simdjson, sqlite, undici, zlib, zstd, libffi, LIEF, perfetto, postject) rather than fetched, so builds are hermetic. — [deps](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/deps)
- `deps/crates` is a Rust staticlib (`crate-type = ["staticlib"]`, `node_crates` v14.6.202, rust-version 1.86) vendoring `temporal_rs`/`temporal_capi` and the ICU4X crates; its Cargo.toml is generated by node-core-utils and must not be hand-edited. — [deps/crates/Cargo.toml](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/deps/crates/Cargo.toml) [deps/crates/crates.gyp](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/deps/crates/crates.gyp) [deps/crates/cargo_build.py](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/deps/crates/cargo_build.py)
- Build/test commands: `./configure && make -j4`, `make test` (tooltest + addon builds + cctest + jstest), `make test-only` (skips doc build), `make test-ci` for CI, `make lint` (js/cpp/md/yaml), `make coverage`. — [Makefile#L343-361](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/Makefile#L343-L361) [Makefile#L644-660](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/Makefile#L644-L660) [Makefile#L1734-1744](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/Makefile#L1734-L1744)
- `configure.py` owns feature toggles that become gyp variables — `--shared-ffi`/`--without-ffi` set `node_use_ffi`, and `--v8-enable-temporal-support` gates the Rust temporal path; `node.gyp` defaults `node_use_ffi%` to `false` and only pulls in `deps/libffi/libffi.gyp:libffi` when it is true. — [configure.py#L771-788](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/configure.py#L771-L788) [configure.py#L2435-2444](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/configure.py#L2435-L2444) [node.gyp#L48](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/node.gyp#L48) [node.gyp#L944-951](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/node.gyp#L944-L951)
- Type checking of `lib/` is opt-in and non-emitting: `tsconfig.json` sets `allowJs: true`, `checkJs: false`, `noEmit: true`, excludes `src`/`tools`, and maps every public builtin id to its `lib/*.js` file plus `internal/*` to `lib/internal/*`. — [tsconfig.json](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/tsconfig.json)
- Hand-written ambient types for the C++ boundary live in `typings/internalBinding/*.d.ts` (one file per binding, including `ffi.d.ts`), loaded via `tsconfig.json`'s `files` list alongside `typings/globals.d.ts` and `typings/primordials.d.ts`. — [typings/internalBinding/ffi.d.ts](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/typings/internalBinding/ffi.d.ts) [typings/globals.d.ts](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/typings/globals.d.ts) [tsconfig.json](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/tsconfig.json)
- Python tooling is linted by ruff configured in `pyproject.toml` with deliberately huge thresholds (`max-complexity = 100`, `max-statements = 289`, `line-length = 172`), reflecting long-lived legacy scripts like `configure.py` (112 KB) and `tools/test.py`. — [pyproject.toml](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/pyproject.toml) [configure.py](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/configure.py)

## Feature catalog

User-facing surface is the CLI plus the `node:*` builtin module set. The CLI's 'subcommands' are really the run-mode branches in `src/node.cc` — `node inspect`, `node --test`, `node --experimental-bench`, `node --watch`, `node -e`, `node --check`, `node --prof-process`, `node --build-snapshot`, `node --build-sea`, and the default script/REPL/stdin paths. Module features are individually flag-gated and only become requirable when a `setupX()` in `pre_execution.js` calls `BuiltinModule.allowRequireByUsers()`. This tree's notable additions over a stock runtime are `node:vfs`, `node:ffi`, `node:dtls`, `node:bench`, `node:quic`, `node:sqlite` with virtual tables, and `stream/iter`/`zlib/iter`.
- `node:vfs` exposes `create()`, `registerProvider()`, and the classes `VirtualFileSystem`, `VirtualProvider`, `MemoryProvider`, `RealFSProvider`, `ZipProvider`; it is `node:`-scheme-only and requires `--experimental-vfs`. — [lib/vfs.js](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/vfs.js) [lib/internal/process/pre_execution.js#L561-569](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/process/pre_execution.js#L561-L569) [doc/api/vfs.md#L28-30](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/doc/api/vfs.md#L28-L30)
- `--vfs-mount <src>` (repeatable) and `--vfs-load <src>` both append to the same `vfs_mounts` option vector; `--vfs-load` additionally sets the `[vfs_load_set]` implied bool so the entry point can be taken from inside a mount. — [src/node_options.cc#L690-713](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/node_options.cc#L690-L713) [src/node_options.h#L181-218](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/node_options.h#L181-L218)
- `node:ffi` provides `DynamicLibrary` plus typed pointer accessors (`getInt8`…`getFloat64`, `setInt8`…, `exportBytes`, `getRawPointer`, `kFastArguments`) and emits an experimental warning at module load. — [lib/ffi.js#L38-60](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/ffi.js#L38-L60) [doc/api/ffi.md#L44-52](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/doc/api/ffi.md#L44-L52)
- `node:bench` mirrors the test runner's API shape — `bench`, `suite`/`describe`, `before`/`after`/`beforeEach`/`afterEach`, `run`, `runFile`, `createRunner` — and is reached from the CLI by `node --experimental-bench`, which routes to `internal/main/bench_runner`. — [lib/bench.js](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/bench.js) [lib/internal/main/bench_runner.js#L17-31](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/main/bench_runner.js#L17-L31) [src/node.cc#L390-393](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/node.cc#L390-L393)
- `node:dtls` exposes `connect`, `listen`, `createSecureContext`, and `DTLSEndpoint`/`DTLSSecureContext`/`DTLSSession`, backed by `src/dtls/{dtls,dtls_context,dtls_endpoint,dtls_session}.cc`; `DTLSEndpoint` manages a UDP socket and routes datagrams to sessions. — [lib/dtls.js](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/dtls.js) [lib/internal/dtls/dtls.js#L525-540](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/dtls/dtls.js#L525-L540) [src/dtls/dtls_endpoint.cc](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/dtls/dtls_endpoint.cc)
- The permission model (`--permission`) exposes `process.permission.has()` / `.drop()` and nine scopes: fs (with read/write children), child, wasi, worker, inspector, net, addon, ffi, openssl.store. — [src/permission/permission_base.h#L17-51](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/permission/permission_base.h#L17-L51) [lib/internal/process/permission.js#L59-67](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/process/permission.js#L59-L67)
- `--permission-audit` is a distinct mode from `--permission`: `isAuditMode()` reads it separately and `Permission::EnableWarningOnly()` makes denials warn rather than throw. — [lib/internal/process/permission.js#L48-58](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/process/permission.js#L48-L58) [src/permission/permission.cc#L302-313](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/permission/permission.cc#L302-L313) [src/node_options.cc#L762](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/node_options.cc#L762)
- Single-executable applications are configured by a JSON file parsed in `src/node_sea.cc` supporting `useSnapshot`, `useCodeCache`, `assets`, and `disableExperimentalSEAWarning`; assets are serialized into the blob and read back as `string_view` pairs. — [src/node_sea.cc#L440-500](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/node_sea.cc#L440-L500) [src/node_sea.cc#L120-240](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/node_sea.cc#L120-L240)
- SEA assets can be surfaced as a read-only mounted VFS via `initSeaVfs()`, which places the SEA main script at the mount-point root so `__dirname`-relative `require()` calls inside a bundled app resolve to bundled assets. — [lib/internal/vfs/sea.js#L24-50](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/vfs/sea.js#L24-L50) [lib/internal/vfs/providers/sea.js#L19-30](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/vfs/providers/sea.js#L19-L30)
- `node --watch` is implemented as a supervisor process: `internal/main/watch_mode.js` strips watch flags into `argsWithoutWatchOptions`, re-`spawn`s `process.execPath`, and drives restarts from a `FilesWatcher` with a 200 ms debounce in `filter` or `all` mode. — [lib/internal/main/watch_mode.js#L21-126](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/main/watch_mode.js#L21-L126)
- The test runner CLI parses options via `parseCommandLine()`, supports `--test-isolation=none` (which defers user-module loading into `run()`), forces concurrency 1 when the inspector is active, and sets a nonzero exit code from the `test:summary` event. — [lib/internal/main/test_runner.js#L19-40](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/main/test_runner.js#L19-L40)
- `--experimental-stream-iter` unlocks two additional builtins in one shot, `stream/iter` and `zlib/iter`, via the same `allowRequireByUsers` mechanism. — [lib/internal/process/pre_execution.js#L533-542](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/process/pre_execution.js#L533-L542)
- `node:sqlite` is enabled by default (disabled only by `--no-experimental-sqlite`) and now supports user-defined virtual tables: `VirtualTableModule` populates an `sqlite3_module` with `xCreate`/`xConnect`/`xBestIndex`/`xOpen`/`xClose` trampolines. — [lib/internal/process/pre_execution.js#L518-525](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/process/pre_execution.js#L518-L525) [src/node_sqlite.cc#L1029-1060](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/node_sqlite.cc#L1029-L1060)
- Documented public API pages exist for every new subsystem — `doc/api/vfs.md`, `ffi.md`, `dtls.md`, `bench.md`, `quic.md`, `stream_iter.md` — so a feature is not considered landed without its doc page. (inferred) — [doc/api/vfs.md](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/doc/api/vfs.md) [doc/api/ffi.md](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/doc/api/ffi.md) [doc/api/bench.md](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/doc/api/bench.md) [doc/api/stream_iter.md](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/doc/api/stream_iter.md)

## Data flow

Input boundaries are argv/env (parsed into `EnvironmentOptions` by `src/node_options.cc` and read from JS via `getOptionValue()`), the file system, sockets, and the SEA blob embedded in the binary. Options are the master state: essentially every JS feature branch keys off `getOptionValue('--flag')`, and options are re-read after deserialization by `refreshRuntimeOptions()`. The heaviest transform in this tree is the VFS path router, which reroutes `node:fs` calls and module-loader fs calls whose resolved path falls under a reserved mount prefix, before those calls reach the native `fs` binding. State owners are the `Environment` object on the C++ side and, on the JS side, module-level singletons: `vfsState.handlers` in `internal/fs/utils.js`, the `loaderOverrides` map in `internal/modules/helpers.js`, the `providers` array in `provider_registry.js`, and `Module._cache`/`_pathCache` in the CJS loader.
- CLI/NODE_OPTIONS parsing populates `EnvironmentOptions` fields declared in `src/node_options.h` (`vfs_mounts`, `experimental_vfs`, `vfs_load`, `allow_fs_vfs`) which JS then reads through `internal/options`'s `getOptionValue()`. — [src/node_options.h#L181-231](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/node_options.h#L181-L231) [src/node_options.cc#L690-713](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/node_options.cc#L690-L713) [lib/internal/process/pre_execution.js#L259-266](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/process/pre_execution.js#L259-L266)
- `refreshRuntimeOptions()` is the first call inside `prepareExecution()`, re-reading options after snapshot deserialization so a snapshotted heap does not carry stale build-time option values. — [lib/internal/process/pre_execution.js#L109-113](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/process/pre_execution.js#L109-L113) [lib/internal/process/pre_execution.js#L366](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/process/pre_execution.js#L366)
- Every VFS mount is assigned a numeric layer id and is served at `${os.devNull}/vfs/<id>`; because `os.devNull` is a character device (`/dev/null`, `\\.\NUL`) it can have no children, so path ownership is decidable from the string alone without touching the disk. — [lib/internal/vfs/router.js#L11-37](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/vfs/router.js#L11-L37)
- `getLayerIdFromPath()` parses the layer id with a hand-rolled digit scan over char codes 47/92 (`/`, `\`) rather than splitting — a deliberate hot-path optimisation since it runs on candidate fs calls. — [lib/internal/vfs/router.js#L39-61](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/vfs/router.js#L39-L61)
- Dispatch into the VFS is a single null-check per fs function: `lib/fs.js` reads `vfsState.handlers` and, if non-null, calls the handler and routes the returned promise through `vfsResult()`/`vfsVoid()` to the error-first callback; when no VFS is mounted the field is `null` and overhead is one comparison. — [lib/fs.js#L208-259](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/fs.js#L208-L259) [lib/internal/fs/utils.js#L1189-1192](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/fs/utils.js#L1189-L1192)
- `setVfsHandlers()` is the only writer of `vfsState.handlers` and is imported by `internal/vfs/setup.js`, making that file the single install point for fs interception. — [lib/internal/fs/utils.js#L1192](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/fs/utils.js#L1192) [lib/internal/vfs/setup.js#L33](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/vfs/setup.js#L33)
- Module resolution is redirected separately from `fs`: `internal/modules/helpers.js` wraps each native loader method and consults a `loaderOverrides` map installed by `setLoaderOverrides()`, with a `hasLoaderOverrides` boolean short-circuit when the map is empty. — [lib/internal/modules/helpers.js#L132-155](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/modules/helpers.js#L132-L155)
- `internal/modules/run_main.js` deliberately calls loader methods through `loaderMethods` rather than the `modules` binding directly, precisely so a mounted VFS can override them and a worker entry point can live inside one. — [lib/internal/modules/run_main.js#L9-12](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/modules/run_main.js#L9-L12)
- Unmounting must invalidate loader state: `cleanForVfsPrefix()` walks `Module._cache`, `Module._pathCache`, `statCache`, `realpathCache`, and the package.json caches, deleting entries under a mount prefix — by value for `_pathCache`, whose keys are `request\0parent` tokens. — [lib/internal/modules/helpers.js#L158-200](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/modules/helpers.js#L158-L200)
- The provider selection pipeline is source-sniffing, not extension-based: `canHandle()` for `zip` attempts `ZipFile.openSync()` (which locates the end-of-central-directory record) and stashes the opened archive in `pendingZipFile` so `create()` does not reopen it; `dir` falls back to `stats.isDirectory()`. — [lib/internal/vfs/provider_registry.js#L23-56](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/vfs/provider_registry.js#L23-L56)
- Permission denials feed a diagnostics channel: `Permission::is_scope_granted` calls `Publish()` on failure, which emits `{scope, resource, dropped}` on a per-scope channel and guards against recursion with a `publishing_` flag so a subscriber's own checks cannot re-enter. — [src/permission/permission.cc#L325-360](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/permission/permission.cc#L325-L360)
- `normalizeReference()` in the JS permission layer canonicalises input across three representations — `URL` (converted with `fileURLToPath` only for `fs.*` scopes), `Uint8Array` (passed through raw so non-UTF-8 paths are not mangled), and validated strings. — [lib/internal/process/permission.js#L17-41](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/process/permission.js#L17-L41)
- SEA data flows binary→memory: `WriteSingleExecutableBlob` serialises the asset map with a length-prefixed count, and the reader rebuilds an `unordered_map<string_view, string_view>` pointing into the still-mapped blob rather than copying. — [src/node_sea.cc#L120-240](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/node_sea.cc#L120-L240)
- Worker threads receive their entry through the message port (`LOAD_SCRIPT` in `internal/worker/io`), not argv, and call `finishVfsMounts()` themselves so mounts are re-created per thread rather than shared. — [lib/internal/main/worker_thread.js#L16-45](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/main/worker_thread.js#L16-L45) [src/node_worker.cc#L705-710](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/node_worker.cc#L705-L710)

## Behavior traces

Three flows characterise the runtime: cold startup of a script, mounting a VFS and loading an entry point from inside it, and a permission-checked FFI `dlopen`. All three share the same spine — C++ picks a main script, that script calls `prepareExecution()`, and `prepareExecution()` decides what the realm is allowed to do. The VFS trace is the most intricate because mounting is deliberately deferred past `--import` preloads so a preload can register a custom provider. The FFI trace is the clearest example of a two-check security path, where a purely in-memory operation still demands filesystem-write permission for platform-consistency reasons.
- Cold start (script): `main()` → `node::Start` → `sea::FixupArgsForSEA` → `StartInternal` → `LoadSnapshotData` → `NodeMainInstance::Run` → C++ `StartExecution` picks `internal/main/run_main_module`. — [src/node_main.cc#L95-99](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/node_main.cc#L95-L99) [src/node.cc#L1716-1735](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/node.cc#L1716-L1735) [src/node.cc#L404-407](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/node.cc#L404-L407)
- `run_main_module.js` then calls `prepareMainThreadExecution(!isEntryURL)` → `markBootstrapComplete()` → `RegExpPrototypeExec(/^/, '')` to reset RegExp statics before user code → `Module.runMain(mainEntry)`. — [lib/internal/main/run_main_module.js#L13-33](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/main/run_main_module.js#L13-L33)
- `Module.runMain` is invoked even for ESM entry points solely to preserve legacy monkey-patchability of `Module.runMain` by `--require` preloads; the file comments this as undesirable and slated for removal once module customization hooks suffice. — [lib/internal/main/run_main_module.js#L20-33](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/main/run_main_module.js#L20-L33) [lib/internal/modules/cjs/loader.js#L520](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/modules/cjs/loader.js#L520)
- Inside `prepareExecution()` the order is fixed: `refreshRuntimeOptions()` → `patchProcessObject()` → trace/inspector/navigator/warning setup → the feature `setupX()` block → `initializeReport()` → `setupDiagnosticsChannel()` → `initializePermission()` → source maps → deprecations → `setupVmModules()` → `initializeModuleLoaders()` → `finishVfsMounts()` → `setupHttpProxy()`. — [lib/internal/process/pre_execution.js#L109-198](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/process/pre_execution.js#L109-L198)
- Each flag-gated builtin is unlocked by the same three lines — check `getOptionValue('--experimental-X')`, require `BuiltinModule` from `internal/bootstrap/realm`, call `allowRequireByUsers('X')` — repeated verbatim in `setupBench`, `setupFFI`, `setupSQLite`, `setupStreamIter`, `setupDTLS`, `setupQuic`, `setupVfs`. — [lib/internal/process/pre_execution.js#L499-569](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/process/pre_execution.js#L499-L569) [lib/internal/bootstrap/realm.js#L275-285](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/bootstrap/realm.js#L275-L285)
- VFS mount trace: `finishVfsMounts()` guards on `vfsMounted` → reads `--vfs-mount` entries → `path.resolve` + `fs.statSync` each (throwing `ERR_VFS_INVALID_TARGET` on failure or on a non-file/non-dir) → `selectProvider()` → `new VirtualFileSystem(provider)` → `vfs.mount()`. — [lib/internal/process/pre_execution.js#L259-296](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/process/pre_execution.js#L259-L296) [lib/internal/vfs/file_system.js#L179-196](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/vfs/file_system.js#L179-L196)
- Mounting is called from two places with an idempotence guard: from `prepareExecution()` only when `--import` is empty, otherwise from `run_main` after the `--import` loop — so an `--import` preload can `registerProvider()` before any source's provider is chosen. — [lib/internal/process/pre_execution.js#L186-192](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/process/pre_execution.js#L186-L192) [lib/internal/modules/run_main.js#L144-152](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/modules/run_main.js#L144-L152)
- For `--vfs-load`, `getVfsLoadIndex()` re-walks `process.execArgv`-style option names to recover which position in the shared `vfs_mounts` list came from `--vfs-load`, because the option parser stores plain strings and cannot record provenance. — [lib/internal/process/pre_execution.js#L219-253](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/process/pre_execution.js#L219-L253)
- The `--vfs-load` source is spliced into `process.argv` at index 1 rather than overwriting it, so the program's own first positional argument is not silently dropped; `argv[1]` names the real source while the reserved mount point stays an implementation detail. — [lib/internal/process/pre_execution.js#L291-303](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/process/pre_execution.js#L291-L303)
- `src/node.cc` routes to `run_main_module` when `vfs_load` is set even with no positional argument, instead of falling through to the REPL or stdin-eval — a dedicated branch added for this flag. — [src/node.cc#L400-407](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/node.cc#L400-L407)
- FFI trace: `new ffi.DynamicLibrary(path)` → `DynamicLibrary::New` → construct-call check → `THROW_IF_INSUFFICIENT_PERMISSIONS(kFFI)` → null-byte check on the path → optional byte materialisation → `uv_dlopen` → `image.AfterOpen()`. — [src/node_ffi.cc#L493-570](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/node_ffi.cc#L493-L570)
- When an FFI library is supplied as bytes (a library living inside a VFS that `dlopen` cannot reach by path), the code additionally demands `kFileSystemWrite` on `AddonImage::TempDir()` — and comments that the check is enforced even on Linux where an anonymous memfd is used, so grants do not vary by platform. — [src/node_ffi.cc#L533-556](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/node_ffi.cc#L533-L556)
- `initializePermission()` hardens the realm before granting: it replaces `process.binding` with a thrower, `ObjectFreeze`s the `path` module so it cannot be monkey-patched to defeat path checks, emits `SecurityWarning` codes PERM0001–PERM0007 for each dangerous `--allow-*`, and only then defines `process.permission`. — [lib/internal/process/permission.js#L1-10](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/process/permission.js#L1-L10) [lib/internal/process/pre_execution.js#L815-878](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/process/pre_execution.js#L815-L878)
- Without `--permission`, passing any `--allow-*` flag is a hard error: the else-branch iterates `availableFlags()` and throws `ERR_MISSING_OPTION`, preventing a false sense of restriction. — [lib/internal/process/pre_execution.js#L878-886](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/process/pre_execution.js#L878-L886) [lib/internal/process/permission.js#L66-88](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/process/permission.js#L66-L88)
- Worker startup diverges: `internal/main/worker_thread.js` calls `prepareWorkerThreadExecution()` (which asserts `initializeModules === false`), waits for a `LOAD_SCRIPT` message on the env message port, and only then calls `initializeModuleLoaders` and `finishVfsMounts`. — [lib/internal/main/worker_thread.js#L16-45](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/main/worker_thread.js#L16-L45) [lib/internal/process/pre_execution.js#L69-80](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/process/pre_execution.js#L69-L80) [lib/internal/process/pre_execution.js#L170-176](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/process/pre_execution.js#L170-L176)

## Testing signals

Testing is dominated by the bespoke Python harness `tools/test.py`, which discovers suites under `test/<suite>/`, applies per-suite `.status` files for SKIP/SLOW/FLAKY expectations, and shells out to the built `node` binary per test file. There is no Vitest/Jest; the stack tag is misleading. Native code is covered by `cctest` (googletest) and the `js-native-api`/`node-api`/`addons` suites, which require a build step before they can run. Coverage is collected by nyc/c8 with `.nycrc` thresholds of 95% lines/statements and 93% branches, uploaded to Codecov from two Linux workflows. The new subsystems are well covered at the JS level — ~121 `test-vfs-*` files in `test/parallel` alone plus a dedicated `test/ffi/` suite — but SEA-specific paths are explicitly excluded from coverage.
- The harness is `tools/test.py`, a Python 3 runner invoked as `./tools/test.py --flaky-tests keep_retrying -p actions -j 4`; suites are directories under `test/` and each may carry a `<section>.status` file read by `ReadConfigurationInto`. — [tools/test.py#L860-870](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/tools/test.py#L860-L870) [tools/test.py#L1391](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/tools/test.py#L1391) [.github/workflows/test-linux.yml#L93-99](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/.github/workflows/test-linux.yml#L93-L99)
- `test/root.status` encodes mode-dependent expectations (e.g. a long list of `parallel/test-*: SLOW` entries under `[$mode==debug]`), and `test/ffi/ffi.status` skips `test-ffi-calls`, `test-ffi-shared-buffer`, and `test-ffi-weakref-calls` on Solaris/SmartOS where bundled libffi callbacks crash. — [test/root.status#L1-30](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/test/root.status#L1-L30) [test/ffi/ffi.status](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/test/ffi/ffi.status)
- `test/parallel` is by far the largest suite (~4976 files), followed by `test/fixtures` (~6108 support files), `test/es-module` (246), `test/addons` (185), `test/sequential` (125), `test/module-hooks` (114), and `test/test-runner` (113). — [test/parallel](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/test/parallel) [test/es-module](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/test/es-module) [test/module-hooks](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/test/module-hooks)
- VFS has roughly 121 dedicated files in `test/parallel` covering per-API parity (`test-vfs-fs-mkdirSync`, `test-vfs-fs-copyFileSync`, `test-vfs-fs-createReadStream`), edge cases (`test-vfs-bigint-position`, `test-vfs-ctime-update`), and an explicit `test-vfs-fs-matches-real-fs` differential test. — [test/parallel/test-vfs-fs-matches-real-fs.js](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/test/parallel/test-vfs-fs-matches-real-fs.js) [test/parallel/test-vfs-bigint-position.js](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/test/parallel/test-vfs-bigint-position.js) [test/parallel/test-vfs-fd.js](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/test/parallel/test-vfs-fd.js)
- FFI has its own compiled suite `test/ffi/` with a `fixture_library`, a `testcfg.py`, and permission-focused tests: `test-ffi-permissions.js`, `test-ffi-permission-allow-cli.js`, `test-ffi-permission-audit.js`, `test-ffi-permission-drop.js`, plus `test-ffi-vfs.js` for the load-from-bytes path. — [test/ffi/test-ffi-permissions.js](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/test/ffi/test-ffi-permissions.js) [test/ffi/test-ffi-permission-audit.js](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/test/ffi/test-ffi-permission-audit.js) [test/ffi/test-ffi-vfs.js](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/test/ffi/test-ffi-vfs.js) [test/ffi/testcfg.py](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/test/ffi/testcfg.py)
- Running the JS suites requires native build steps first: `make jstest` depends on `build-addons build-js-native-api-tests build-node-api-tests build-sqlite-tests build-ffi-tests` — running `tools/test.py` on a clean tree will fail those suites. — [Makefile#L323](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/Makefile#L323) [Makefile#L343-361](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/Makefile#L343-L361)
- `make cctest` runs the C++ googletest binary built from `test/cctest/` (37 files) and is a separate gate from the JS suites. — [Makefile#L304](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/Makefile#L304) [test/cctest](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/test/cctest) [deps/googletest](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/deps/googletest)
- CI suite composition is `CI_JS_SUITES = $(JS_SUITES) pummel` and `CI_NATIVE_SUITES = $(NATIVE_SUITES) benchmark`, with `doctool` conditionally appended; `make test-ci` runs all three plus the prerequisite builds. — [Makefile#L610-615](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/Makefile#L610-L615) [Makefile#L644-650](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/Makefile#L644-L650)
- `.github/workflows/test-linux.yml` builds on ubuntu-24.04 and ubuntu-24.04-arm with clang-19, Python 3.14, Rust 1.88 and sccache, runs `make build-ci` then `make test-ci -j1 TEST_CI_ARGS="-p actions --measure-flakiness 9"`. — [.github/workflows/test-linux.yml#L40-92](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/.github/workflows/test-linux.yml#L40-L92)
- CI asserts test hygiene two ways: a `git add -A && git diff --exit-code --staged` step fails the build if running tests dirtied the tree, and the whole suite is re-run from a directory named with spaces, quotes, and non-ASCII characters to catch path-handling bugs. — [.github/workflows/test-linux.yml#L89-99](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/.github/workflows/test-linux.yml#L89-L99)
- Coverage thresholds are declared in `.nycrc` — 95% lines, 95% statements, 93% branches — over `lib/` only, with `test/`, `tools/`, `benchmark/`, and `deps/` excluded. — [.nycrc](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/.nycrc)
- Codecov is configured to wait for two coverage builds (`coverage-linux.yml` and `coverage-linux-without-intl.yml`; the Windows one is noted as manually disabled) and both project and patch status gates are turned off, so coverage is informational rather than blocking. — [codecov.yml](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/codecov.yml) [.github/workflows/coverage-linux.yml](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/.github/workflows/coverage-linux.yml) [.github/workflows/coverage-linux-without-intl.yml](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/.github/workflows/coverage-linux-without-intl.yml)
- `test/common/index.js` exposes capability predicates that tests use to self-skip — `hasCrypto`, `hasIntl`, `hasFullICU`, `hasTemporal`, `hasDtls`, `hasQuic`, `hasSQLite`, `hasFFI`, `hasInspector`, `hasLocalStorage` — so conditionally-compiled bindings do not produce false failures. — [test/common/index.js#L1008-1033](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/test/common/index.js#L1008-L1033)
- SEA-plus-VFS initialisation is explicitly uncovered: `internal/vfs/sea.js` opens with `/* c8 ignore start -- SEA VFS initialization requires an actual SEA binary */`, so that path is exercised only by the separate `test/sea` suite (43 files), not by line coverage. — [lib/internal/vfs/sea.js#L22](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/vfs/sea.js#L22) [test/sea](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/test/sea)
- Recent commit history shows active flake management (`test: deflake test-bench-errors`, `test-http2-debug`, `test-benchmark-crypto`) alongside a `label-flaky-test-issue.yml` workflow and `--measure-flakiness 9` in CI. — [.github/workflows/label-flaky-test-issue.yml](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/.github/workflows/label-flaky-test-issue.yml) [.github/workflows/stress-test.yml](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/.github/workflows/stress-test.yml) [.github/workflows/test-linux.yml#L92](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/.github/workflows/test-linux.yml#L92)

## Risk map

The highest-value security surfaces are the permission model, `node:ffi`, and the VFS path router — and they interact. FFI is a documented memory-unsafe API whose only guard is the `kFFI` scope; the VFS is documented as explicitly *not* a security boundary despite superficially resembling a sandbox; and the permission model's correctness depends on non-obvious hardening (freezing `path`, killing `process.binding`) that a refactor could silently undo. Fragile coupling concentrates in the VFS's reliance on string-prefix path ownership and on cache invalidation across five separate module-loader caches. The `--vfs-load` provenance recovery by re-parsing execArgv is the most brittle single mechanism in the tree.
- `node:ffi` is memory-unsafe by design — the docs state that invalid pointers, wrong signatures, or use-after-free 'can crash the process or corrupt memory' — and its only gate is `THROW_IF_INSUFFICIENT_PERMISSIONS(kFFI)`, which is a no-op unless `--permission` is on. — [doc/api/ffi.md#L16-19](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/doc/api/ffi.md#L16-L19) [src/node_ffi.cc#L503](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/node_ffi.cc#L503) [src/permission/permission.cc#L314-320](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/permission/permission.cc#L314-L320)
- `--allow-ffi` is only offered in `availableFlags()` when `--experimental-ffi` is set, so the flag surface changes shape depending on another flag; a script probing `availableFlags()` for capability discovery can get inconsistent answers. — [lib/internal/process/permission.js#L66-88](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/process/permission.js#L66-L88)
- The VFS is documented as NOT a sandbox: 'The VFS API is not a sandbox, permission system, or access-control mechanism', and `RealFSProvider`'s root-escape rejection is explicitly stated not to be a security boundary. Any code treating a mount as isolation is wrong. — [doc/api/vfs.md#L30-47](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/doc/api/vfs.md#L30-L47)
- VFS path ownership is decided purely by string prefix against `${os.devNull}/vfs`; the safety argument rests on `os.devNull` being a character device that cannot have children. A platform where that assumption fails, or a `path.resolve` normalisation difference, would break routing exactness. — [lib/internal/vfs/router.js#L11-37](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/vfs/router.js#L11-L37) [lib/internal/vfs/file_system.js#L52-63](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/vfs/file_system.js#L52-L63)
- `getVfsLoadIndex()` recovers which mount came from `--vfs-load` by re-walking argument names and counting `--vfs-mount`/`--vfs-load` occurrences, including manual handling of the space-separated `--vfs-mount value` form. Any change to option parsing or aliasing silently misattributes the entry point. — [lib/internal/process/pre_execution.js#L219-253](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/process/pre_execution.js#L219-L253)
- Unmount correctness depends on `cleanForVfsPrefix()` clearing five distinct caches (`Module._cache`, `Module._pathCache` by value, `statCache`, `realpathCache`, package.json caches); missing one leaves resolvable stale entries pointing into an unmounted layer. — [lib/internal/modules/helpers.js#L158-200](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/modules/helpers.js#L158-L200) [lib/internal/vfs/file_system.js#L196-211](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/vfs/file_system.js#L196-L211)
- The permission model's integrity relies on two side effects that look like incidental hardening: replacing `process.binding` with a thrower and `ObjectFreeze(require('path'))`. Removing either reopens a documented bypass. — [lib/internal/process/pre_execution.js#L817-823](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/process/pre_execution.js#L817-L823)
- `Permission::Publish` guards re-entrancy with a mutable `publishing_` flag rather than a scope guard; an exception thrown from a diagnostics-channel subscriber would leave `publishing_` stuck true and silently suppress all further permission telemetry. — [src/permission/permission.cc#L340-360](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/permission/permission.cc#L340-L360)
- Zip provider detection performs a trial `ZipFile.openSync()` inside `canHandle()` and caches the handle in module-level `pendingZipFile`; if a later provider's `canHandle` throws or `create()` is never reached, that file handle leaks and a subsequent probe reuses stale state. — [lib/internal/vfs/provider_registry.js#L23-47](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/vfs/provider_registry.js#L23-L47)
- `registerProvider()` unshifts onto a module-global array with no removal API and no ordering control beyond 'newest wins', and the doc comment confirms a registered provider 'can back, wrap, or vet any source' — a `--require`/`--import` preload can therefore intercept every subsequent mount. — [lib/internal/vfs/provider_registry.js#L58-80](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/vfs/provider_registry.js#L58-L80) [lib/internal/process/pre_execution.js#L186-192](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/process/pre_execution.js#L186-L192)
- `node --watch` shells out: it `spawn`s `process.execPath` with reconstructed argv and manipulates `NODE_OPTIONS`, making it a command-construction path where flag stripping bugs change what the child is allowed to do (a recent commit addressed exactly this: 'watch: strip watch flags from NODE_OPTIONS in child process'). — [lib/internal/main/watch_mode.js#L26-126](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/main/watch_mode.js#L26-L126)
- `src/node_file.cc` is the largest source file (5851 lines) and contains ~55 `THROW_IF_INSUFFICIENT_PERMISSIONS` call sites; each new fs syscall wrapper is an opportunity to omit one, and there is no compile-time enforcement that a binding method performs its check. — [src/node_file.cc](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/node_file.cc) [src/permission/permission.h](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/permission/permission.h)
- Blast radius: `lib/internal/process/pre_execution.js` is on the critical path of every execution mode (main thread, worker, shadow realm, test runner, bench runner), so a fault in any `setupX()` breaks all entry points at once. — [lib/internal/process/pre_execution.js#L49-108](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/process/pre_execution.js#L49-L108) [lib/internal/main/test_runner.js#L23](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/main/test_runner.js#L23) [lib/internal/main/bench_runner.js#L17](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/main/bench_runner.js#L17)
- `--vfs-load` is force-disabled for workers by mutating `per_isolate_opts->per_env->vfs_load = false` in `src/node_worker.cc`; this cross-layer write means main-thread and worker option state intentionally diverge, which is easy to overlook when reasoning about option values in JS. — [src/node_worker.cc#L705-710](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/node_worker.cc#L705-L710)
- SEA construction writes an executable to disk from a JSON config with `assets` and `useSnapshot`/`useCodeCache`, and `FixupArgsForSEA` rewrites argv before any option parsing — a supply-chain-relevant path where the config file fully determines the resulting binary's behaviour. — [src/node_sea.cc#L440-500](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/node_sea.cc#L440-L500) [src/node.cc#L1727-1740](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/node.cc#L1727-L1740)

## Extension points

This codebase is unusually explicit about where new code plugs in, because adding a feature is a repeated four-part ritual. New native capability goes in the `NODE_BUILTIN_*_BINDINGS` macro lists; new CLI surface goes in `src/node_options.cc` with a field in `node_options.h`; new run modes go in the `StartExecution` if-chain plus a file in `lib/internal/main/`; new user-visible builtins are gated by a `setupX()` in `pre_execution.js` calling `BuiltinModule.allowRequireByUsers()`. Beyond core, the VFS provider registry, the CJS `Module._extensions` table, the loader-override map, and the SQLite virtual-table module are genuine runtime plugin surfaces.
- `BuiltinModule.allowRequireByUsers(id)` is the runtime gate that makes a `lib/*.js` module requirable by user code; it adds to `canBeRequiredByUsersList` and conditionally to `canBeRequiredByUsersWithoutSchemeList` (new experimental modules are added `node:`-scheme-only). — [lib/internal/bootstrap/realm.js#L275-311](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/bootstrap/realm.js#L275-L311)
- `vfs.registerProvider({ name, canHandle, create })` is the public plugin interface for `--vfs-mount` sources; registrations are unshifted ahead of the built-in `zip` and `dir` providers, so a custom provider outranks both. — [lib/internal/vfs/provider_registry.js#L58-90](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/vfs/provider_registry.js#L58-L90) [lib/vfs.js#L33-40](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/vfs.js#L33-L40)
- `VirtualProvider` in `lib/internal/vfs/provider.js` is the base class a custom provider subclasses; the shipped implementations (`MemoryProvider`, `RealFSProvider`, `ZipProvider`, and the internal SEA provider) are the reference shapes. — [lib/internal/vfs/provider.js](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/vfs/provider.js) [lib/internal/vfs/providers/memory.js](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/vfs/providers/memory.js) [lib/internal/vfs/providers/ziparchive.js](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/vfs/providers/ziparchive.js) [lib/internal/vfs/providers/sea.js](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/vfs/providers/sea.js)
- `setLoaderOverrides(overrides)` installs per-key replacements for the module loader's fs and package.json operations; passing a nullish field restores the native fast path, which is how unmount cheaply reverts loader interception. — [lib/internal/modules/helpers.js#L138-155](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/modules/helpers.js#L138-L155)
- `Module._extensions` is the classic CJS extension table (`.js`, `.json`, `.node` assigned in `cjs/loader.js`) and `findLongestRegisteredExtension` supports multi-dot extensions, so a loader plugin can register e.g. `.test.ts`. — [lib/internal/modules/cjs/loader.js#L399](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/modules/cjs/loader.js#L399) [lib/internal/modules/cjs/loader.js#L626-641](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/modules/cjs/loader.js#L626-L641) [lib/internal/modules/cjs/loader.js#L2052-2125](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/modules/cjs/loader.js#L2052-L2125)
- `Module._load`, `Module._resolveFilename`, and `Module._findPath` remain intentionally monkey-patchable — `resolveMainPath()` comments that `Module._findPath` 'is monkey-patchable here', and the repo's own `eslint.config.mjs` patches `Module._resolveFilename` to resolve vendored ESLint plugins. — [lib/internal/modules/run_main.js#L31-37](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/modules/run_main.js#L31-L37) [lib/internal/modules/cjs/loader.js#L1341](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/modules/cjs/loader.js#L1341) [eslint.config.mjs#L37-46](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/eslint.config.mjs#L37-L46)
- Adding a native binding means adding `V(name)` to the appropriate macro list in `src/node_binding.h` — `NODE_BUILTIN_STANDARD_BINDINGS` for unconditional ones, or a new `#if`-guarded `NODE_BUILTIN_X_BINDINGS(V)` block for optional subsystems. — [src/node_binding.h#L28-81](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/node_binding.h#L28-L81)
- Adding a CLI flag is a paired edit: `AddOption("--flag", help, BOOL_FIELD(field), kAllowedInEnvvar-style)` in `src/node_options.cc` and the field declaration in `src/node_options.h`; `Implies()` links derived bools (as `--vfs-load` implies `[vfs_load_set]`). — [src/node_options.cc#L690-713](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/node_options.cc#L690-L713) [src/node_options.h#L181-231](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/node_options.h#L181-L231)
- Adding an execution mode requires a branch in the `StartExecution` chain in `src/node.cc` and a corresponding script in `lib/internal/main/`; `bench_runner` is the most recent instance of this pattern and mirrors `test_runner` line for line. — [src/node.cc#L390-395](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/node.cc#L390-L395) [lib/internal/main/bench_runner.js](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/main/bench_runner.js) [lib/internal/main/test_runner.js](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/main/test_runner.js)
- `sqlite.createModule()` backed by `VirtualTableModule` lets user JS supply `xBestIndex`/`xOpen`/`xClose` behaviour into SQLite's `sqlite3_module` vtable — a genuine C++-level plugin surface reachable from JS. — [src/node_sqlite.cc#L1029-1060](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/node_sqlite.cc#L1029-L1060)
- Permission scopes are extended by adding a `V(Name, "dotted.name", Parent, "--allow-flag")` entry to the `PERMISSIONS(V)` macro in `permission_base.h`; the enum, the diagnostics channel names, and the string mapping are all generated from it. — [src/permission/permission_base.h#L17-58](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/permission/permission_base.h#L17-L58) [src/permission/permission.cc#L340-378](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/permission/permission.cc#L340-L378)
- Test suites are pluggable: each `test/<suite>/` may carry a `testcfg.py` and a `<suite>.status` file that `tools/test.py` discovers, as `test/ffi/` does. — [test/ffi/testcfg.py](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/test/ffi/testcfg.py) [test/ffi/ffi.status](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/test/ffi/ffi.status) [tools/test.py#L860-870](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/tools/test.py#L860-L870)
- Lint is composed from per-directory partial configs (`lib/eslint.config_partial.mjs`, `test/`, `doc/`, `benchmark/`, `tools/eslint/`) assembled by the root `eslint.config.mjs`, plus a custom `tools/eslint-rules` plugin directory — the place to add core-specific rules. — [eslint.config.mjs#L5-29](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/eslint.config.mjs#L5-L29) [lib/eslint.config_partial.mjs](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/eslint.config_partial.mjs) [test/eslint.config_partial.mjs](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/test/eslint.config_partial.mjs)
- The internal binding type surface is extended by adding a `typings/internalBinding/<name>.d.ts` file; recent commits ('typings: wire up quic internal binding types', 'typings: add mksnapshot internal binding types') show this is expected alongside the C++ change. (inferred) — [typings/internalBinding/ffi.d.ts](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/typings/internalBinding/ffi.d.ts) [typings/internalBinding/inspector.d.ts](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/typings/internalBinding/inspector.d.ts) [tsconfig.json](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/tsconfig.json)

## Contributor handoff

Read `AGENTS.md` first — it is binding policy, not advice, and it forbids an agent from pushing, opening PRs, or posting comments without active human oversight. Code style in `lib/` is not ordinary JavaScript: everything goes through `primordials` to be immune to user monkey-patching, and a custom ESLint plugin enforces it. Before editing, understand that `lib/` is snapshotted at build time, so top-level side effects in bootstrap files have outsized consequences. Nothing in `deps/` should be hand-edited. The realistic verification loop is a full build followed by targeted `tools/test.py` runs, not a fast unit-test cycle.
- `AGENTS.md` requires `Signed-off-by:` from the human contributor and an `Assisted-by: <agent name>` annotation, and explicitly prohibits `Signed-off-by:`/`Co-authored-by:` naming an agent, pushing to any branch or tag, and creating unsupervised PRs or issues. — [AGENTS.md](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/AGENTS.md)
- Read these first, in order: `AGENTS.md`, `CONTRIBUTING.md`, `doc/contributing/primordials.md`, `doc/contributing/cpp-style-guide.md`, and `lib/internal/bootstrap/node.js` (whose header comment is the best single explanation of startup ordering). — [AGENTS.md](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/AGENTS.md) [CONTRIBUTING.md](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/CONTRIBUTING.md) [doc/contributing/primordials.md](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/doc/contributing/primordials.md) [lib/internal/bootstrap/node.js#L1-48](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/bootstrap/node.js#L1-L48)
- Every file in `lib/` destructures from `primordials` at the top (`ArrayPrototypePush`, `StringPrototypeStartsWith`, `ObjectFreeze`, …) instead of using built-in methods directly; new code must match this or `tools/eslint-rules` will reject it. — [lib/internal/vfs/provider_registry.js#L8-10](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/vfs/provider_registry.js#L8-L10) [lib/internal/process/permission.js#L3-7](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/process/permission.js#L3-L7) [doc/contributing/primordials.md](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/doc/contributing/primordials.md) [eslint.config.mjs#L29](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/eslint.config.mjs#L29)
- Never hand-edit `deps/`: `deps/crates/Cargo.toml` states 'This manifest is generated by node-core-utils. Do not modify it directly', and dependency bumps are driven by `tools/dep_updaters/` and scheduled workflows. — [deps/crates/Cargo.toml#L1](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/deps/crates/Cargo.toml#L1) [tools/dep_updaters](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/tools/dep_updaters) [.github/workflows/update-v8.yml](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/.github/workflows/update-v8.yml) [.github/workflows/update-openssl.yml](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/.github/workflows/update-openssl.yml)
- Anything added to `lib/internal/bootstrap/` must be synchronous and must not read argv or env at top level, because it is executed at snapshot-build time; runtime-dependent setup belongs in `pre_execution.js` or a `lib/internal/main/` script. — [lib/internal/bootstrap/node.js#L18-27](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/bootstrap/node.js#L18-L27)
- Verification loop: `./configure && make -j<n>` then `python3 tools/test.py parallel/test-<pattern>` for targeted runs; full validation is `make test-only` (build addons + cctest + jstest + tooltest without rebuilding docs). — [Makefile#L353-361](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/Makefile#L353-L361) [tools/test.py#L1391](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/tools/test.py#L1391) [BUILDING.md](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/BUILDING.md)
- Lint before proposing a change: `make lint` runs js/cpp/md/yaml; `make lint-ci` adds Python lint and a merge-conflict-marker scan across `benchmark deps doc lib src test tools` that fails the build on stray `<<<<<<<`/`>>>>>>>`. — [Makefile#L1734-1752](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/Makefile#L1734-L1752)
- Safe edit boundary: a feature that is JS-only (a new provider, a runner reporter, a stream helper) can be added without touching C++. Anything needing a new syscall, a new option, or a new permission scope requires coordinated edits across `src/node_options.{cc,h}`, `src/node_binding.h`, and `pre_execution.js`. (inferred) — [src/node_options.cc#L690-713](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/node_options.cc#L690-L713) [src/node_binding.h#L28-81](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/node_binding.h#L28-L81) [lib/internal/process/pre_execution.js#L499-569](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/process/pre_execution.js#L499-L569)
- Trap: options are read twice — once at parse time into `EnvironmentOptions` and again in JS via `getOptionValue()` after `refreshRuntimeOptions()`. Caching an option value at JS module scope before that call yields a stale snapshot-time value. — [lib/internal/process/pre_execution.js#L109-113](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/process/pre_execution.js#L109-L113) [lib/internal/process/pre_execution.js#L366-377](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/process/pre_execution.js#L366-L377)
- Trap: `permission.js` memoizes `_permission`, `_audit`, and `_ffi` on first read, so an option consulted before `refreshRuntimeOptions()` is frozen for the process lifetime. — [lib/internal/process/permission.js#L13-16](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/process/permission.js#L13-L16) [lib/internal/process/permission.js#L44-58](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/lib/internal/process/permission.js#L44-L58)
- Trap: worker option state is not the main thread's — `src/node_worker.cc` overwrites `vfs_load` to false per worker, so a JS-side `getOptionValue('--vfs-load')` reasoning must account for thread identity. — [src/node_worker.cc#L705-710](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/src/node_worker.cc#L705-L710)
- Trap: `test/ffi`, `test/sqlite`, `test/addons`, `test/js-native-api`, and `test/node-api` all need a build step (`make build-ffi-tests`, etc.) before `tools/test.py` will pass on them; failures there on a fresh tree usually mean 'not built', not 'broken'. — [Makefile#L323](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/Makefile#L323) [Makefile#L621-626](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/Makefile#L621-L626)
- CI asserts the tree is unchanged after tests run, so any test that writes into the repo (rather than a tmpdir) will fail the Linux workflow even if the assertions pass. — [.github/workflows/test-linux.yml#L89-92](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/.github/workflows/test-linux.yml#L89-L92)
- Use `test/common/index.js` capability predicates (`hasFFI`, `hasDtls`, `hasQuic`, `hasSQLite`, `hasTemporal`, `hasCrypto`) to guard new tests for conditionally-compiled features rather than assuming a full-featured build. — [test/common/index.js#L1021-1031](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/test/common/index.js#L1021-L1031)
- Public API changes are incomplete without the matching `doc/api/*.md` page and YAML metadata block (`added: vX.Y.Z`, `Stability: 1 - Experimental`), as every subsystem in this tree carries one. — [doc/api/vfs.md#L1-12](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/doc/api/vfs.md#L1-L12) [doc/api/ffi.md#L1-12](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/doc/api/ffi.md#L1-L12) [doc/contributing/api-documentation.md](https://github.com/nodejs/node/blob/976a36a5b6ce737c9e695f6cde8e141427f13737/doc/contributing/api-documentation.md)

Source repository: https://github.com/nodejs/node
Full evidence corpus: https://github.com/Codevetter/codevetter/tree/main/benchmarks/repo-unpacks/node.json

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
