# Data flow — nodejs/node

> Canonical page: https://codevetter.com/unpack/node/data-flow

# Data flow — nodejs/node

Scanned commit 976a36a5b6ce737c9e695f6cde8e141427f13737 (2026-09-22). Generated by codevetter codevetter 1.12.0 on 2026-09-22.

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)

Every claim links to its cited files at the pinned commit. Citations identify source evidence; they do not establish runtime correctness. Independent CodeVetter scan — not reviewed by upstream maintainers.

## Public product links

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