# Extension points — nodejs/node

> Canonical page: https://codevetter.com/unpack/node/extension-points

# Extension points — nodejs/node

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

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)

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)
