An exhaustive reference for engineers, SREs, distribution maintainers, and platform architects who build, deploy, operate, harden, and extend Node.js — the open-source, cross-platform JavaScript runtime built on the V8 engine and libuv asynchronous I/O library. This guide covers everything beneath the application layer: compilation, configuration, security hardening, performance tuning, diagnostics, and deep internals.
For everyday usage — running scripts, installing packages, using the REPL, HTTP servers, and the built-in test runner — see the User Guide.
1. Architecture Overview
1.1 What Node.js Is
Node.js is a single-binary, event-driven JavaScript runtime that executes JavaScript outside the browser. It embeds Google's V8 JavaScript engine for JIT compilation of JavaScript and WebAssembly, couples it with libuv for cross-platform asynchronous I/O, and wraps both in a C++ binding layer that exposes operating system primitives — file systems, networking, cryptography, process management, and more — to JavaScript applications through a standard library of built-in modules.
The runtime follows a single-threaded event loop model for JavaScript execution, delegating blocking operations (file I/O, DNS resolution, compression) to a thread pool managed by libuv. This architecture delivers high concurrency for I/O-bound workloads without the complexity of shared-memory threading. For CPU-bound work, the worker_threads module provides true parallelism with message-passing between isolates.
Node.js ships as a single statically-linked executable (node or node.exe) that bundles 20+ C/C++ dependencies, a JavaScript standard library of 55+ modules, and tooling including a CLI debugger, a built-in test runner, an HTTP/2 server, experimental QUIC support, the Chrome DevTools inspector protocol, and npm (installed alongside). The codebase spans 12,024 files at commit 978a8c40.
Note
Node.js is not a web framework. It is a runtime — the layer that frameworks like Express, Fastify, Koa, and Nest.js run on top of. This guide covers the runtime itself.
1.2 Architecture Diagram
┌─────────────────────────────────────────────────────────────────────┐
│ JavaScript Application │
├─────────────────────────────────────────────────────────────────────┤
│ Node.js Standard Library (lib/) │
│ fs, http, https, net, crypto, stream, child_process, worker_threads│
│ path, url, os, util, events, buffer, dns, tls, zlib, vm, assert │
│ test, readline, cluster, dgram, http2, perf_hooks, diagnostics_ch │
├──────────────┬──────────────────────────────────────────────────────┤
│ Internal │ Internal Modules (lib/internal/) │
│ Bindings │ abort_controller, blob, buffer, child_process, │
│ (C++ ↔ JS) │ crypto, encoding, errors, event_target, fs, http, │
│ │ modules/{cjs,esm}, process, streams, test_runner, │
│ │ timers, tls, url, util, v8, vm, watch_mode, worker │
├──────────────┴──────────────────────────────────────────────────────┤
│ C++ Binding Layer (src/ — 151 files) │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌───────────┐ ┌─────────┐ │
│ │ crypto/ │ │ quic/ │ │inspector/│ │permission/ │ │tracing/ │ │
│ │ 31 files │ │ 18 files │ │ 20 files │ │ 10 files │ │ 6 files │ │
│ │ 138K ch │ │ 159K ch │ │ 39K ch │ │ 19K ch │ │ 115K ch │ │
│ └──────────┘ └──────────┘ └──────────┘ └───────────┘ └─────────┘ │
├─────────────────────────────────────────────────────────────────────┤
│ Dependencies (deps/) │
│ ┌────┐ ┌─────┐ ┌───────┐ ┌──────┐ ┌─────┐ ┌────┐ ┌───────────┐ │
│ │ V8 │ │libuv│ │OpenSSL│ │llhttp│ │c-ares│ │zlib│ │ nghttp2 │ │
│ └────┘ └─────┘ └───────┘ └──────┘ └─────┘ └────┘ └───────────┘ │
│ ┌────────┐ ┌───────┐ ┌─────────┐ ┌───┐ ┌──────┐ ┌────────────┐ │
│ │simdutf │ │simdjson│ │ brotli │ │ada│ │sqlite│ │ngtcp2/ngh3 │ │
│ └────────┘ └───────┘ └─────────┘ └───┘ └──────┘ └────────────┘ │
├─────────────────────────────────────────────────────────────────────┤
│ Operating System (via libuv) │
│ epoll / kqueue / IOCP / event ports / poll │
└─────────────────────────────────────────────────────────────────────┘
1.3 Component Inventory
| Component | Path | Role |
|---|---|---|
| V8 | deps/v8/ |
JavaScript/WebAssembly JIT compiler and garbage collector |
| libuv | deps/uv/ |
Cross-platform async I/O, event loop, thread pool, timers |
| llhttp | deps/llhttp/ |
HTTP/1.1 request/response parser (replaces http-parser) |
| OpenSSL | deps/openssl/ |
TLS/SSL, cryptographic primitives, FIPS support |
| c-ares | deps/cares/ |
Asynchronous DNS resolver |
| ICU | deps/icu-small/ |
Unicode and internationalization (Intl, RegExp Unicode) |
| zlib | deps/zlib/ |
Compression (gzip, deflate, brotli via separate dep) |
| nghttp2 | deps/nghttp2/ |
HTTP/2 protocol implementation |
| brotli | deps/brotli/ |
Brotli compression algorithm |
| simdutf | deps/simdutf/ |
SIMD-accelerated UTF-8/UTF-16 validation and transcoding |
| simdjson | deps/simdjson/ |
SIMD-accelerated JSON parsing |
| ada | deps/ada/ |
WHATWG URL parser (fast, spec-compliant) |
| sqlite | deps/sqlite/ |
Embedded SQL database engine (node:sqlite) |
| ngtcp2 | deps/ngtcp2/ |
QUIC protocol implementation |
| nghttp3 | deps/nghttp3/ |
HTTP/3 protocol over QUIC |
| LIEF | Single Executable Application resource injection | |
| libffi | src/ (2 files) |
Foreign Function Interface (experimental) |
| undici | deps/undici/ |
HTTP client (backing fetch() implementation) |
| cjs-module-lexer | deps/cjs-module-lexer/ |
Fast CommonJS named-export detection |
| acorn | deps/acorn/ |
JavaScript parser used by internal tooling |
| googletest | deps/googletest/ |
C++ unit testing framework for native tests |
1.4 Technology Stack
| Layer | Technology |
|---|---|
| Language (runtime core) | C++17 |
| Language (standard library) | JavaScript (ES2024+) |
| Build system | GYP (Generate Your Projects) via configure.py + node_gyp |
| Build backends | make, ninja |
| JavaScript engine | V8 (current V8 version bundled with release) |
| Event loop | libuv |
| HTTP parsing | llhttp |
| TLS | OpenSSL (3.x) |
| Package manager | npm (bundled) |
| Test framework | Built-in node:test + custom harness in test/common/ |
| Documentation | Markdown in doc/api/, processed by tools/doc/ |
| CI | GitHub Actions, Jenkins |
1.5 Data Flow
Event Loop Cycle
┌───────────────────────────┐
│ timers (setTimeout, │
│ setInterval) │
└───────────┬───────────────┘
│
┌───────────▼───────────────┐
│ pending callbacks │
│ (deferred I/O callbacks)│
└───────────┬───────────────┘
│
┌───────────▼───────────────┐
│ idle, prepare │
│ (internal use) │
└───────────┬───────────────┘
│
┌───────────▼───────────────┐
│ poll │ ← epoll/kqueue/IOCP waits here
│ (I/O callbacks) │ for new I/O events
└───────────┬───────────────┘
│
┌───────────▼───────────────┐
│ check (setImmediate) │
└───────────┬───────────────┘
│
┌───────────▼───────────────┐
│ close callbacks │
│ (socket.on('close')) │
└───────────┘
│
process.nextTick() and ← runs between EVERY phase
microtask queue (Promises)
Module Resolution Flow
require('module')orimport 'module'invoked- If
node:prefix, load built-in module directly fromlib/ - Check
node_modules/hierarchy (CJS) or resolve viapackage.jsonexports map (ESM) - CJS:
lib/internal/modules/cjs/loader.js— synchronousModule._resolveFilename()→Module._load()→ compile → cache - ESM:
lib/internal/modules/esm/— asyncresolve()→load()→translate()→instantiate()through loader chain - Native addons (
.nodefiles):process.dlopen()→ dynamic library load →napi_register_module_v1init
HTTP Request Lifecycle
- TCP connection arrives → libuv accepts →
net.Socketcreated - Data arrives → libuv callback →
llhttpparses HTTP headers/body http.IncomingMessage+http.ServerResponseobjects created- User handler invoked (
requestevent) - Response written → buffered by streams → flushed to socket
- Socket drained → keep-alive or close
2. System Requirements
2.1 Supported Platforms
| Platform | Architectures | Tier |
|---|---|---|
| Linux (glibc ≥ 2.28) | x64, arm64, armv7, ppc64le, s390x, riscv64, loong64 | Tier 1 (x64, arm64), Tier 2 (others) |
| macOS (≥ 11.0) | x64, arm64 (Apple Silicon) | Tier 1 |
| Windows (≥ 10 / Server 2016) | x64, arm64 | Tier 1 (x64), Tier 2 (arm64) |
| FreeBSD (≥ 13) | x64 | Tier 2 |
| SmartOS (illumos) | x64 | Tier 2 |
| IBM i (PASE) | ppc64 | Tier 2 |
| z/OS | s390x | Tier 2 |
| Android | arm64 | Experimental |
| MIPS-based Linux | mips64el | Experimental |
2.2 Architecture Support Matrix
| Architecture | Linux | macOS | Windows |
|---|---|---|---|
| x64 (amd64) | Full | Full | Full |
| arm64 (aarch64) | Full | Full (M1/M2/M3+) | Supported |
| armv7 (32-bit ARM) | Supported | N/A | N/A |
| ppc64le | Supported | N/A | N/A |
| s390x | Supported | N/A | N/A |
| riscv64 | Experimental | N/A | N/A |
| loong64 | Experimental | N/A | N/A |
2.3 Build Prerequisites
| Prerequisite | Version | Notes |
|---|---|---|
| Python | 3.8+ | Required for configure.py and GYP build generation |
| C++ compiler | GCC 10.1+ / Clang 8+ / MSVC 2022+ | Must support C++17 |
| make | GNU Make 3.81+ | Or ninja as alternative |
| ninja | 1.7+ | Optional, faster builds (--ninja) |
| Git | 2.x | For cloning and development |
| nasm | 2.13+ | Required for OpenSSL asm on x86/x64 |
| pkg-config | Any | For detecting shared libraries |
| ccache | Any | Optional, speeds up rebuilds |
Linux (Debian/Ubuntu):
sudo apt-get install -y python3 g++ make git nasm pkg-config
Linux (RHEL/Fedora):
sudo dnf install -y python3 gcc-c++ make git nasm pkg-config
macOS:
xcode-select --install # Installs clang, make, git
brew install python nasm
Windows:
Install Visual Studio 2022 with "Desktop development with C++" workload. Python 3 must be on PATH. The build uses vcbuild.bat instead of configure.py/make.
2.4 Build Configuration — configure.py Reference
The configure.py script accepts 190+ flags via argparse, generating GYP build files. Flags are grouped by category below.
General Build Options
| Flag | Default | Description |
|---|---|---|
--prefix |
/usr/local |
Installation prefix directory |
--dest-cpu |
auto-detect | Target CPU: x64, arm, arm64, ia32, mips64el, ppc64, riscv64, s390x, loong64 |
--dest-os |
auto-detect | Target OS: linux, mac, win, freebsd, android, aix |
--ninja |
off | Generate ninja build files instead of Makefiles |
--verbose |
off | Verbose build output |
--tag |
(none) | Custom build tag |
--release-urlbase |
(none) | Base URL for release downloads |
--enable-d8 |
off | Build V8's d8 shell |
--gdb |
off | Add GDB support |
--no-ifaddrs |
off | Disable getifaddrs() usage |
--fully-static |
off | Generate fully static binary |
--partly-static |
off | Static libgcc/libstdc++, shared libc |
--write-snapshot |
off | Write a startup snapshot blob |
--without-npm |
off | Do not install npm |
--without-corepack |
off | Do not install corepack |
--with-snapshot |
on | Build with V8 snapshot for faster startup |
--without-snapshot |
off | Build without V8 snapshot |
--node-snapshot-main |
(none) | Main script for custom startup snapshot |
--coverage |
off | Build with code coverage instrumentation |
--error-on-warn |
off | Treat compiler warnings as errors |
Debug Options
| Flag | Default | Description |
|---|---|---|
--debug |
off | Build with debug symbols (-g), no optimization |
--debug-node |
off | Debug Node.js C++ only (not V8 or deps) |
--debug-lib |
off | No-op; debug JS with --inspect at runtime |
--enable-asan |
off | Build with AddressSanitizer |
--enable-msan |
off | Build with MemorySanitizer |
--enable-tsan |
off | Build with ThreadSanitizer |
--enable-ubsan |
off | Build with UndefinedBehaviorSanitizer |
--enable-lsan |
off | Build with LeakSanitizer |
--enable-static-analysis |
off | Enable Clang static analysis |
--v8-lite-mode |
off | V8 lite mode (reduced memory, no JIT) |
--v8-enable-disassembler |
off | Enable V8 disassembler |
--v8-enable-object-print |
off | Enable V8 object printing |
--v8-enable-hugepage |
off | V8 hugepage support (Linux) |
--v8-enable-short-builtin-calls |
off | Short builtin calls (perf optimization) |
--v8-enable-31bit-smis-on-64bit-arch |
off | 31-bit SMIs on 64-bit |
--v8-enable-pointer-compression |
varies | V8 pointer compression |
--v8-enable-shared-ro-heap |
off | Shared read-only heap across isolates |
--v8-enable-i18n-support |
on | V8 internationalization support |
--v8-enable-inspector |
on | V8 inspector protocol support |
Shared Library Options
| Flag | Default | Description |
|---|---|---|
--shared |
off | Build libnode as a shared library |
--shared-http-parser |
off | Link against system llhttp (not bundled) |
--shared-libuv |
off | Link against system libuv |
--shared-nghttp2 |
off | Link against system nghttp2 |
--shared-openssl |
off | Link against system OpenSSL |
--shared-zlib |
off | Link against system zlib |
--shared-brotli |
off | Link against system brotli |
--shared-cares |
off | Link against system c-ares |
--shared-ngtcp2 |
off | Link against system ngtcp2 |
--shared-nghttp3 |
off | Link against system nghttp3 |
--shared-simdjson |
off | Link against system simdjson |
--shared-simdutf |
off | Link against system simdutf |
--shared-sqlite |
off | Link against system sqlite |
--shared-ada |
off | Link against system ada URL parser |
--shared-uvwasi |
off | Link against system uvwasi |
--with-ltcg |
off | Link-Time Code Generation (MSVC only) |
--without-bundled-v8 |
off | Use system V8 (advanced, rarely used) |
For each --shared-* flag, corresponding --shared-*-includes and --shared-*-libpath flags specify custom include and library paths.
Crypto / SSL Options
| Flag | Default | Description |
|---|---|---|
--openssl-conf-name |
nodejs_conf |
OpenSSL configuration section name |
--openssl-default-cipher-list |
(OpenSSL default) | Override default TLS cipher list |
--openssl-no-asm |
off | Disable OpenSSL assembly optimizations |
--openssl-fips |
off | Build OpenSSL with FIPS module |
--openssl-is-fips |
off | Report crypto.getFips() as enabled |
--openssl-use-def-ca-store |
off | Use OpenSSL's default CA store |
--openssl-system-ca-path |
(none) | Path to system CA certificates |
--without-ssl |
off | Build without TLS/crypto support entirely |
--without-node-options |
off | Disallow NODE_OPTIONS env var |
Important
Building with
--without-ssldisables thecrypto,tls,https, andhttp2modules entirely. Most production applications require TLS. Only use this for deeply embedded or constrained environments.
ICU / Internationalization Options
| Flag | Default | Description |
|---|---|---|
--with-intl |
full-icu |
ICU mode: full-icu (all locales), small-icu (English only), system-icu, none |
--with-icu-source |
(bundled) | Path to custom ICU source tarball or directory |
--with-icu-default-data-dir |
(none) | Default ICU data directory at runtime |
--without-intl |
off | Alias for --with-intl=none |
--download |
none |
Download missing ICU data during configure |
Platform-Specific Options
| Flag | Platform | Description |
|---|---|---|
--enable-pgo-generate |
Linux/macOS | Emit profile data for PGO builds (step 1) |
--enable-pgo-use |
Linux/macOS | Use PGO profile data for optimized build (step 2) |
--cross-compiling |
Any | Force cross-compilation mode |
--link-module |
Any | Additional JS module to link into the binary |
--node-builtin-modules-path |
Any | Override path for built-in JS modules (development) |
--enable-vtune-profiling |
Linux/Windows | Enable Intel VTune Profiler integration |
--enable-etw |
Windows | Enable Event Tracing for Windows |
--with-ossfuzz |
Linux | Build for OSS-Fuzz fuzzing |
--with-arm-float-abi |
ARM | Float ABI: hard, soft, softfp |
--with-arm-fpu |
ARM | ARM FPU: vfp, vfpv3, vfpv3-d16, neon |
--with-mips-arch-variant |
MIPS | MIPS variant: r1, r2, r6 |
--with-mips-fpu-mode |
MIPS | MIPS FPU: fp32, fp64, fpxx |
Experimental Options
| Flag | Default | Description |
|---|---|---|
--experimental-http-parser |
off | Use experimental HTTP parser |
--node-use-node-snapshot |
on | Use Node.js startup snapshot |
--without-node-snapshot |
off | Disable Node.js snapshot |
--without-node-code-cache |
off | Disable Node.js code cache |
--disable-single-executable-application |
off | Disable SEA support |
2.5 Building from Source
Standard build:
git clone https://github.com/nodejs/node.git
cd node
./configure
make -j$(nproc)
# Binary at ./out/Release/node
Ninja build (faster):
./configure --ninja
ninja -C out/Release
Debug build:
./configure --debug
make -j$(nproc)
# Binary at ./out/Debug/node
Installation:
sudo make install
# Installs to /usr/local by default
# Change with: ./configure --prefix=/opt/node
Windows build:
vcbuild.bat release x64
:: Binary at Release\node.exe
Profile-Guided Optimization (PGO):
# Step 1: Build instrumented binary
./configure --enable-pgo-generate
make -j$(nproc)
# Step 2: Run workload to generate profile data
./out/Release/node your-benchmark.js
# Step 3: Build optimized binary using profile
./configure --enable-pgo-use
make -j$(nproc)
3. Configuration Reference
3.1 Runtime Environment Variables
| Variable | Default | Description |
|---|---|---|
NODE_ENV |
(unset) | Application environment. production disables some dev features. Not read by Node.js core, but widely used by frameworks. |
NODE_OPTIONS |
(unset) | Space-separated list of CLI flags applied before command-line flags. Security-sensitive: can inject --require. Disable with --without-node-options at build time. |
NODE_PATH |
(unset) | Colon-separated (; on Windows) list of directories prepended to module search path. Legacy; prefer node_modules hierarchy. |
NODE_DEBUG |
(unset) | Comma-separated list of core modules to emit debug output: fs, http, net, tls, module, timer, stream, child_process, cluster. |
NODE_DEBUG_NATIVE |
(unset) | Enable debug output for C++ internals. |
NODE_TLS_REJECT_UNAUTHORIZED |
1 |
Set to 0 to disable TLS certificate validation. Never use in production. |
NODE_EXTRA_CA_CERTS |
(unset) | Path to PEM file with extra CA certificates appended to the default trust store. |
NODE_ICU_DATA |
(unset) | Path to ICU data file for small-icu builds that need full locale data at runtime. |
NODE_NO_WARNINGS |
(unset) | Set to 1 to suppress all process warnings. |
NODE_PENDING_DEPRECATION |
(unset) | Set to 1 to emit pending deprecation warnings. |
NODE_PENDING_PIPE_INSTANCES |
4 |
Number of pending pipe instances for IPC on Windows. |
NODE_REDIRECT_WARNINGS |
(unset) | Path to file for writing warnings instead of stderr. |
NODE_REPL_HISTORY |
~/.node_repl_history |
Path to REPL history file. Set to empty string to disable. |
NODE_REPL_EXTERNAL_MODULE |
(unset) | Path to alternative REPL module. |
NODE_DISABLE_COLORS |
(unset) | Set to 1 to disable ANSI colors in REPL and util output. |
NODE_V8_COVERAGE |
(unset) | Directory to write V8 code coverage data (JSON). |
NODE_COMPILE_CACHE |
(unset) | Directory for module compile cache. Speeds up repeated startup. |
NODE_CHANNEL_FD |
(unset) | File descriptor for parent/child IPC channel (internal). |
NODE_CLUSTER_SCHED_POLICY |
rr |
Cluster scheduling: rr (round-robin) or none (OS-decided). |
NODE_UNIQUE_ID |
(unset) | Cluster worker ID (set automatically by cluster master). |
NODE_TEST_CONTEXT |
(unset) | Internal test runner context variable. |
UV_THREADPOOL_SIZE |
4 |
libuv thread pool size (1–1024). Affects fs, dns.lookup(), crypto, zlib. |
UV_USE_IO_URING |
0 |
Set to 1 to enable io_uring on Linux (experimental in libuv). |
OPENSSL_CONF |
(system) | Path to OpenSSL configuration file. |
SSL_CERT_DIR |
(system) | Directory containing CA certificates in PEM format. |
SSL_CERT_FILE |
(system) | Path to CA certificate bundle file. |
TZ |
(system) | Timezone for Date objects. Uses ICU/system timezone database. |
FORCE_COLOR |
(unset) | Force color output (0=none, 1=16 colors, 2=256, 3=16M). |
NO_COLOR |
(unset) | Disable all color output (any value). |
NODE_MACOSX_PERF |
(unset) | Enable macOS performance tools integration. |
Important
NODE_OPTIONSis a powerful injection point. In multi-tenant or shared hosting environments, restrict it by building Node.js with--without-node-optionsor by clearing it in process startup scripts.
3.2 package.json Configuration
| Field | Type | Description |
|---|---|---|
"type" |
"module" or "commonjs" |
Module system for .js files. "module" = ESM, "commonjs" = CJS (default). |
"main" |
string | CJS entry point (used when package is require()d). |
"exports" |
object/string | Conditional exports map. Controls what consumers can import/require. |
"imports" |
object | Subpath imports — private package-internal import mappings (e.g., #utils). |
"engines" |
object | Engine version constraints: { "node": ">=18.0.0" }. Advisory only unless enforced by package manager. |
"scripts" |
object | Lifecycle scripts: start, test, preinstall, postinstall, etc. |
"bin" |
string/object | CLI executable mappings. |
"files" |
array | Allowlist of files to include when publishing. |
"dependencies" |
object | Production dependencies. |
"devDependencies" |
object | Development-only dependencies. |
"peerDependencies" |
object | Peer dependency declarations. |
"optionalDependencies" |
object | Optional dependencies (install failures non-fatal). |
"overrides" |
object | Dependency version overrides (npm) / "resolutions" (yarn). |
3.3 OpenSSL Configuration
Node.js loads OpenSSL configuration from the section specified by --openssl-conf-name (default: nodejs_conf) in the OpenSSL config file. Override the config file path with the OPENSSL_CONF environment variable.
# /etc/ssl/openssl.cnf (excerpt)
[nodejs_conf]
ssl_conf = ssl_sect
[ssl_sect]
system_default = system_default_sect
[system_default_sect]
MinProtocol = TLSv1.2
CipherString = DEFAULT:@SECLEVEL=2
3.4 V8 Flags Passthrough
V8 accepts hundreds of tuning flags passed through --v8-options or via NODE_OPTIONS:
# List all V8 flags
node --v8-options
# Pass specific V8 flags
node --max-old-space-size=8192 --max-semi-space-size=64 app.js
# Experimental V8 features
node --harmony-temporal app.js
Key V8 flags for production tuning are covered in Section 6 (Performance).
4. Deployment & Scaling
4.1 Production Deployment Patterns
Process Manager Deployment (PM2)
# Install PM2
npm install -g pm2
# Start application with clustering
pm2 start app.js -i max --name my-app
# Save process list for system restart
pm2 save
pm2 startup systemd
systemd Service
# /etc/systemd/system/node-app.service
[Unit]
Description=Node.js Application
After=network.target
[Service]
Type=simple
User=nodeapp
WorkingDirectory=/opt/app
ExecStart=/usr/local/bin/node --max-old-space-size=4096 app.js
Restart=on-failure
RestartSec=5
Environment=NODE_ENV=production
# Security hardening
NoNewPrivileges=true
ProtectSystem=strict
ReadWritePaths=/opt/app/data
PrivateTmp=true
[Install]
WantedBy=multi-user.target
sudo systemctl enable node-app
sudo systemctl start node-app
4.2 Docker Deployment
# Multi-stage build
FROM node:22-slim AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
FROM node:22-slim
WORKDIR /app
COPY --from=build /app .
USER node
EXPOSE 3000
ENV NODE_ENV=production
CMD ["node", "app.js"]
Tip
Use
node:22-slim(Debian slim) ornode:22-alpinefor smaller images. The slim variant is ~200MB vs ~1GB for the full image. Alpine uses musl libc, which can cause subtle compatibility issues with native addons.
Docker health check:
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
CMD node -e "require('http').get('http://localhost:3000/health', (r) => process.exit(r.statusCode === 200 ? 0 : 1))"
4.3 Cluster Module (Multi-Process)
The cluster module forks the Node.js process to utilize multiple CPU cores:
import cluster from 'node:cluster';
import http from 'node:http';
import os from 'node:os';
if (cluster.isPrimary) {
const cpuCount = os.cpus().length;
for (let i = 0; i < cpuCount; i++) {
cluster.fork();
}
cluster.on('exit', (worker, code, signal) => {
console.error(`Worker ${worker.process.pid} died (${signal || code}). Restarting...`);
cluster.fork();
});
} else {
http.createServer((req, res) => {
res.writeHead(200);
res.end('OK');
}).listen(3000);
}
Scheduling policy is controlled by NODE_CLUSTER_SCHED_POLICY:
rr(default on all platforms except Windows): Round-robin distribution by the primary process.none: OS decides which worker gets the connection (can lead to uneven distribution).
4.4 Worker Threads (Multi-Threaded)
Worker threads share the same process and can share memory via SharedArrayBuffer:
import { Worker, isMainThread, parentPort, workerData } from 'node:worker_threads';
if (isMainThread) {
const worker = new Worker(new URL(import.meta.url), {
workerData: { input: [1, 2, 3, 4, 5] }
});
worker.on('message', (result) => console.log('Result:', result));
} else {
const sum = workerData.input.reduce((a, b) => a + b, 0);
parentPort.postMessage(sum);
}
Worker threads are best for CPU-intensive operations (image processing, compression, ML inference). For I/O-bound work, the event loop with async I/O is more efficient.
4.5 Single Executable Applications (SEA)
Build a standalone binary that bundles the application into the Node.js executable:
// sea-config.json
{
"main": "app.js",
"output": "sea-prep.blob",
"disableExperimentalSEAWarning": true,
"useSnapshot": false,
"useCodeCache": true,
"assets": {
"icon.png": "assets/icon.png"
}
}
# 1. Generate the SEA preparation blob
node --experimental-sea-config sea-config.json
# 2. Copy the Node.js binary
cp $(which node) my-app
# 3. Inject the blob into the binary
# Linux:
npx postject my-app NODE_SEA_BLOB sea-prep.blob \
--sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2
# macOS: add --macho-segment-name NODE_SEA
# Windows: use signtool for code signing after injection
4.6 Startup Snapshots
Build a snapshot of application startup state into the binary for near-instant cold starts:
# Build Node.js with custom snapshot
./configure --node-snapshot-main=app.js
make -j$(nproc)
# The resulting binary starts with app.js already initialized
Runtime snapshot building:
node --build-snapshot --snapshot-blob snapshot.blob app.js
node --snapshot-blob snapshot.blob
Note
Snapshots capture the V8 heap state at snapshot time. Not all objects serialize correctly — avoid capturing open file descriptors, network sockets, or native addon state in the snapshot.
5. Operations
5.1 Health Monitoring
// health.js — production health check endpoint
import http from 'node:http';
import v8 from 'node:v8';
import os from 'node:os';
http.createServer((req, res) => {
if (req.url === '/health') {
const heap = v8.getHeapStatistics();
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
status: 'ok',
uptime: process.uptime(),
memory: {
rss: process.memoryUsage.rss(),
heapUsed: heap.used_heap_size,
heapTotal: heap.total_heap_size,
heapLimit: heap.heap_size_limit,
external: process.memoryUsage().external
},
cpu: process.cpuUsage(),
eventLoopLag: performance.now(), // measure with perf_hooks for real lag
pid: process.pid,
loadAvg: os.loadavg()
}));
}
}).listen(9090);
Tip
Use
perf_hooks.monitorEventLoopDelay()for production-grade event loop monitoring. A histogram-based approach is more accurate than sampling:import { monitorEventLoopDelay } from 'node:perf_hooks'; const h = monitorEventLoopDelay({ resolution: 20 }); h.enable(); // h.percentile(99) gives p99 event loop delay in nanoseconds
5.2 Diagnostic Reports
Diagnostic reports produce a JSON summary of process state (stack traces, heap stats, libuv handles, environment, loaded modules) for post-mortem debugging:
# Generate on signal
node --report-on-signal app.js
kill -USR2 <pid>
# Generate on fatal error (uncaught exception, OOM)
node --report-on-fatalerror app.js
# Generate on uncaught exception
node --report-uncaught-exception app.js
# Generate programmatically
node -e "process.report.writeReport('report.json')"
# Configure report directory and filename
node --report-directory=/var/log/node-reports --report-filename=diag-{pid}-{datetime}.json app.js
# Compact report format
node --report-compact app.js
Report output includes:
- Header (event, date, PID, Node.js/V8/libuv versions)
- JavaScript stack trace
- Native stack trace
- Heap statistics
- Resource usage (user CPU, system CPU, max RSS)
- libuv handle summary (active handles/requests)
- Environment variables
- Loaded shared libraries
- Workers (if any)
5.3 CPU Profiling
# V8 CPU profiler (outputs .cpuprofile for Chrome DevTools)
node --cpu-prof --cpu-prof-dir=./profiles --cpu-prof-interval=100 app.js
# V8 tick processor profiling (lower level)
node --prof app.js
node --prof-process isolate-0x*.log > profile.txt
# Linux perf integration
perf record -g node --perf-basic-prof app.js
perf report
5.4 Heap Analysis
# Heap snapshot on signal
node --heapsnapshot-signal=SIGUSR2 app.js
kill -USR2 <pid>
# Produces Heap.*.heapsnapshot — load in Chrome DevTools
# Programmatic heap snapshot
node -e "
const v8 = require('v8');
const fs = require('fs');
const snapshotStream = v8.writeHeapSnapshot();
console.log('Heap snapshot written to:', snapshotStream);
"
# Heap profiling (allocation tracking)
node --heap-prof --heap-prof-dir=./profiles app.js
Tip
For memory leak detection in production, use
--heapsnapshot-signalto take snapshots on demand without restarting. Compare snapshots in Chrome DevTools to identify retained objects.
5.5 Tracing
Node.js includes a built-in tracing system compatible with Chrome's chrome://tracing:
# Enable trace events
node --trace-events-enabled --trace-event-categories=v8,node,node.async_hooks app.js
# Available trace categories:
# v8 - V8 engine events (GC, compilation)
# node - Node.js core events
# node.async_hooks - Async hooks trace events
# node.bootstrap - Bootstrap/startup events
# node.environment - Environment lifecycle
# node.fs.sync - Synchronous fs operations
# node.fs.async - Asynchronous fs operations
# node.net.native - Network events (TCP, DNS)
# node.dns.native - DNS resolution events
# node.perf - Performance events
# node.perf.usertiming - User timing marks/measures
# node.perf.timerify - Timerified function traces
# Output is written to node_trace.*.log in the current directory
The tracing subsystem is implemented in src/tracing/ (6 files, 115K chars) and integrates with V8's trace event infrastructure.
5.6 Inspector Protocol
Node.js implements the Chrome DevTools Protocol (CDP) for debugging, profiling, and automation:
# Start with inspector (accepts connections on 127.0.0.1:9229)
node --inspect app.js
# Break on first line
node --inspect-brk app.js
# Listen on all interfaces (CAUTION: security risk)
node --inspect=0.0.0.0:9229 app.js
# Wait for debugger to attach before starting
node --inspect-wait app.js
# Inspect in a running process
kill -SIGUSR1 <pid> # Opens inspector on default port
Warning
Never expose the inspector port to untrusted networks. The inspector protocol allows arbitrary code execution. Use SSH tunneling or a reverse proxy with authentication for remote debugging:
ssh -L 9229:localhost:9229 user@remote-host
The inspector implementation lives in src/inspector/ (20 files, 39K chars) and includes WebSocket transport, V8 inspector client bindings, and the inspector module API.
5.7 Watch Mode
# Restart on file changes (built-in, no external tools needed)
node --watch app.js
# Watch mode with path filtering
node --watch-path=./src --watch-path=./config app.js
# Watch mode preserves the process state (experimental)
node --watch-preserve-output app.js
Watch mode is implemented in lib/internal/watch_mode/ and uses fs.watch() (backed by inotify/FSEvents/ReadDirectoryChangesW) for efficient file system monitoring.
5.8 Graceful Shutdown
// Graceful shutdown pattern
const server = http.createServer(handler);
server.listen(3000);
const connections = new Set();
server.on('connection', (conn) => {
connections.add(conn);
conn.on('close', () => connections.delete(conn));
});
function shutdown(signal) {
console.log(`Received ${signal}. Graceful shutdown...`);
// Stop accepting new connections
server.close(() => {
console.log('Server closed. Exiting.');
process.exit(0);
});
// Set a hard timeout
setTimeout(() => {
console.error('Forced shutdown after timeout');
process.exit(1);
}, 30000).unref();
// Destroy idle connections
for (const conn of connections) {
conn.end();
}
}
process.on('SIGTERM', () => shutdown('SIGTERM'));
process.on('SIGINT', () => shutdown('SIGINT'));
Note
.unref()on the timeout timer prevents it from keeping the event loop alive. Without it, the process would wait the full 30 seconds even if all connections close immediately.
6. Performance
6.1 Event Loop Optimization
The event loop is the heart of Node.js performance. Key principles:
- Never block the event loop — long synchronous operations (JSON.parse on large payloads, RegExp backtracking, synchronous crypto) stall all concurrent connections.
- Partition CPU work — use
setImmediate()to break large synchronous tasks across event loop ticks. - Offload to worker threads — CPU-intensive operations (image encoding, hashing large files) should use
worker_threads. - Monitor event loop delay — p99 > 100ms indicates problems.
// Partition a large array operation
function processChunk(items, index, chunkSize, callback) {
const end = Math.min(index + chunkSize, items.length);
for (let i = index; i < end; i++) {
// process items[i]
}
if (end < items.length) {
setImmediate(() => processChunk(items, end, chunkSize, callback));
} else {
callback();
}
}
6.2 Large Pages
Large pages (huge pages) reduce TLB misses for the V8 code region, improving performance by 5-10% for some workloads:
# Linux: configure huge pages
sudo sysctl -w vm.nr_hugepages=100
echo 'vm.nr_hugepages=100' | sudo tee -a /etc/sysctl.conf
# Run Node.js with large pages
node --use-largepages=on app.js
# Options: on, silent (don't warn on failure), off
The large pages implementation lives in src/large_pages/ and maps the V8 code region to 2MB pages on Linux (or equivalent on other platforms).
6.3 V8 Tuning
| Flag | Default | Description |
|---|---|---|
--max-old-space-size |
~1.7GB (64-bit) | Maximum old generation heap size in MB. Increase for memory-intensive apps. |
--max-semi-space-size |
16MB | Maximum semi-space (nursery) size in MB. Increase for high-allocation-rate apps. |
--max-heap-size |
(calculated) | Overall heap limit in MB. |
--initial-old-space-size |
(calculated) | Initial old generation size in MB. |
--initial-heap-size |
(calculated) | Initial heap size in MB. Pre-allocating reduces GC pauses during startup. |
--optimize-for-size |
off | Optimize V8 for memory usage over speed. |
--always-compact |
off | Force full GC compaction (slower but reduces fragmentation). |
--expose-gc |
off | Expose global.gc() for manual GC triggering. |
--trace-gc |
off | Log GC events to stderr. |
--trace-gc-verbose |
off | Verbose GC logging. |
--gc-interval |
(auto) | Force GC every N allocations (debugging only). |
--noconcurrent-recompilation |
off | Disable concurrent JIT compilation. |
--predictable |
off | Deterministic mode (disables concurrent GC/compilation). For testing. |
# Production: 8GB heap, aggressive semi-space for high-throughput server
node --max-old-space-size=8192 --max-semi-space-size=64 app.js
# Memory-constrained environment (container with 512MB limit)
node --max-old-space-size=384 --optimize-for-size app.js
# Debug GC behavior
node --trace-gc --trace-gc-verbose app.js 2>gc.log
6.4 Startup Optimization
| Technique | Mechanism | Speedup |
|---|---|---|
| Code cache | V8 compiles and caches bytecode; subsequent loads skip parsing | 10-30% startup |
| Startup snapshot | Heap state serialized at build time; deserialized on start | 40-70% startup |
| Compile cache | NODE_COMPILE_CACHE dir caches compiled module bytecode across runs |
10-30% startup |
| Lazy loading | require() modules only when first used |
Proportional to unused modules |
| SEA with code cache | "useCodeCache": true in SEA config |
Combined benefits |
# Enable module compile cache
export NODE_COMPILE_CACHE=/tmp/node-compile-cache
node app.js # First run: compiles and caches
node app.js # Subsequent: loads from cache
6.5 Thread Pool Tuning
libuv's thread pool handles fs operations, dns.lookup(), and some crypto/zlib calls:
# Default: 4 threads. Max: 1024.
export UV_THREADPOOL_SIZE=16 # Must be set BEFORE process starts
node app.js
Guidelines:
- Increase if
fsordns.lookup()latency is high under load - Don't over-provision — each thread consumes ~1MB stack. 64 threads = 64MB just for stacks
- Use
dns.resolve()(c-ares, async, not threadpool) instead ofdns.lookup()(getaddrinfo, threadpool) for high-volume DNS
6.6 Benchmark Infrastructure
The benchmark/ directory contains a comprehensive benchmark suite:
# Run a specific benchmark
node benchmark/http/simple.js
# Run benchmark comparison between two Node.js builds
node benchmark/compare.js --old /path/to/old/node --new /path/to/new/node -- benchmark/http/
# Common benchmark categories:
# benchmark/http/ HTTP server throughput
# benchmark/fs/ File system operations
# benchmark/streams/ Stream throughput
# benchmark/buffers/ Buffer operations
# benchmark/url/ URL parsing
# benchmark/crypto/ Cryptographic operations
# benchmark/child_process/ Process spawning
# benchmark/events/ EventEmitter performance
# benchmark/net/ TCP networking
# benchmark/path/ Path operations
# benchmark/string_decoder/ String decoding
# benchmark/timers/ Timer performance
7. Security
7.1 Permission Model
Node.js implements an experimental permission model (since v20) that restricts what a Node.js process can do:
# Enable permission model (denies everything by default)
node --experimental-permission app.js
# Grant specific permissions
node --experimental-permission \
--allow-fs-read=/app/data \
--allow-fs-write=/app/output \
app.js
# Allow child process spawning
node --experimental-permission \
--allow-child-process \
app.js
# Allow worker threads
node --experimental-permission \
--allow-worker \
app.js
# Allow native addons
node --experimental-permission \
--allow-addons \
app.js
# Wildcard patterns
node --experimental-permission \
--allow-fs-read=/app/* \
--allow-fs-write=/tmp/* \
app.js
Warning
The permission model is experimental. It provides defense-in-depth but is not a security sandbox. Malicious native addons or V8 exploits can bypass it. Do not rely on it as the sole security boundary.
The permission system is implemented in src/permission/ (10 files, 19K chars):
| Permission Class | Scope |
|---|---|
AddonPermission |
Loading native addon .node files |
ChildProcessPermission |
Spawning child processes (child_process.spawn, exec, etc.) |
FFIPermission |
Foreign Function Interface calls (experimental node:ffi) |
FSPermission |
File system read/write access (path-based) |
WorkerPermission |
Creating Worker threads |
Check permissions programmatically:
if (process.permission.has('fs.read', '/etc/passwd')) {
// Permission granted
}
7.2 TLS/SSL Configuration
import tls from 'node:tls';
import https from 'node:https';
import fs from 'node:fs';
const server = https.createServer({
key: fs.readFileSync('private-key.pem'),
cert: fs.readFileSync('certificate.pem'),
ca: fs.readFileSync('ca-chain.pem'),
// Minimum TLS version (default: TLSv1.2)
minVersion: 'TLSv1.2',
// Cipher suite configuration
ciphers: [
'TLS_AES_256_GCM_SHA384',
'TLS_CHACHA20_POLY1305_SHA256',
'TLS_AES_128_GCM_SHA256',
'ECDHE-RSA-AES256-GCM-SHA384',
'ECDHE-RSA-AES128-GCM-SHA256'
].join(':'),
// ECDH curve
ecdhCurve: 'auto',
// Request client certificate
requestCert: true,
rejectUnauthorized: true,
// Session resumption
sessionTimeout: 300,
// ALPN protocols
ALPNProtocols: ['h2', 'http/1.1'],
// Disable renegotiation (prevents DoS)
// Node.js disables renegotiation by default since v16
// OCSP stapling
// Handled via 'OCSPRequest' event on tls.Server
}, handler);
Caution
Never set
NODE_TLS_REJECT_UNAUTHORIZED=0in production. It disables all certificate validation, making every TLS connection vulnerable to man-in-the-middle attacks. For self-signed certificates, useNODE_EXTRA_CA_CERTSor thecaoption.
7.3 OpenSSL and FIPS Mode
Node.js links against OpenSSL 3.x for all cryptographic operations. FIPS 140-2/3 compliance requires:
# Build-time: configure with FIPS
./configure --openssl-fips
# Or: mark as FIPS-capable
./configure --openssl-is-fips
# Runtime: enable FIPS mode
node --enable-fips app.js
# Or force FIPS (error if cannot enable)
node --force-fips app.js
// Check FIPS status
import crypto from 'node:crypto';
console.log('FIPS enabled:', crypto.getFips());
// Enable FIPS programmatically
crypto.setFips(1);
7.4 Crypto Module Security
The src/crypto/ subsystem (31 files, 138K chars) wraps OpenSSL and exposes:
| Area | Considerations |
|---|---|
| Hashing | Use sha256 or sha3-256 minimum. MD5 and SHA1 are broken for security purposes. |
| Symmetric encryption | Use aes-256-gcm (authenticated) not aes-256-cbc (no integrity check). |
| Key derivation | Use scrypt or argon2 (via native addon) for passwords. PBKDF2 with high iteration count as fallback. |
| Random bytes | crypto.randomBytes() uses OpenSSL's CSPRNG. crypto.randomUUID() for UUIDs. |
| Timing attacks | Use crypto.timingSafeEqual() for constant-time comparison. |
| Key management | Use crypto.generateKeyPair() for RSA/EC keys. Minimum 2048-bit RSA, prefer Ed25519. |
7.5 Supply Chain Security
# Audit dependencies for known vulnerabilities
npm audit
# Fix automatically where possible
npm audit fix
# Production install (no devDependencies, no scripts)
npm ci --only=production --ignore-scripts
# Lock file integrity
npm ci # Always uses package-lock.json exactly
# Verify package signatures (npm v9+)
npm audit signatures
7.6 Known Security-Related Issues
| Issue | Status | Description |
|---|---|---|
| #62781 | Open | V8 SIGSEGV with pre-CVE code caches — loading code caches generated by older, vulnerable V8 versions can trigger a segmentation fault. Mitigation: regenerate code caches after Node.js upgrades. |
| #62774 | Open | Missing NULL checks in crypto/quic OpenSSL integration — potential crash on malformed QUIC packets. Affects experimental QUIC only. |
| #62326 | Open | dns.resolveSrv() returns ECONNREFUSED on Windows — DNS resolution issue specific to SRV records on Windows systems. |
7.7 Security Best Practices
- Run as non-root — use a dedicated service account with minimal privileges
- Drop capabilities — on Linux, use
setcapor systemdCapabilityBoundingSet - Disable inspector in production — never expose
--inspectports - Freeze prototypes — use
--frozen-intrinsics(experimental) to prevent prototype pollution - Policy-based module loading — use
--experimental-policywith integrity checks - Limit
NODE_OPTIONS— build with--without-node-optionsor clear before launch - HTTP header limits —
--max-http-header-size(default 16KB) prevents header-based DoS - Request timeout — set
server.requestTimeoutandserver.headersTimeout
8. Developer Internals
8.1 Repository Structure
nodejs/node/
├── src/ C++ binding layer (151 files, 1.3M chars)
│ ├── crypto/ OpenSSL wrappers (31 files, 138K)
│ ├── quic/ QUIC/HTTP3 protocol (18 files, 159K)
│ ├── inspector/ Chrome DevTools Protocol (20 files, 39K)
│ ├── permission/ Permission model (10 files, 19K)
│ ├── tracing/ Trace event infrastructure (6 files, 115K)
│ └── large_pages/ Huge page support
├── lib/ JavaScript standard library
│ ├── *.js 55 top-level modules (898K chars)
│ └── internal/ 52 internal modules (568K chars)
├── deps/ Bundled C/C++ dependencies
│ ├── v8/ V8 JavaScript engine
│ ├── uv/ libuv async I/O
│ ├── openssl/ OpenSSL
│ ├── llhttp/ HTTP parser
│ ├── cares/ Async DNS
│ ├── icu-small/ ICU internationalization
│ ├── nghttp2/ HTTP/2
│ ├── ngtcp2/ QUIC
│ ├── nghttp3/ HTTP/3
│ ├── zlib/ Compression
│ ├── brotli/ Brotli compression
│ ├── simdutf/ SIMD UTF conversion
│ ├── simdjson/ SIMD JSON parsing
│ ├── ada/ URL parser
│ ├── sqlite/ SQLite
│ ├── undici/ HTTP client (fetch)
│ └── ...
├── test/ Test suite (4,000+ files)
├── tools/ Build and development tools
├── benchmark/ Performance benchmarks
├── doc/ API documentation source
├── typings/ TypeScript type definitions for internal C++ bindings
└── configure.py Build configuration script (190+ flags)
8.2 C++ Binding Layer (src/)
The C++ layer bridges V8 and the operating system. Key patterns:
Environment and Isolate
Every Node.js instance creates an Environment object (src/env.h, src/env.cc) that owns:
- The V8
Isolate(single-threaded JS execution context) - The libuv event loop
- All built-in module bindings
- The async hooks state
- The permission model
// Simplified binding registration pattern
void Initialize(Local<Object> target, Local<Value> unused,
Local<Context> context, void* priv) {
Environment* env = Environment::GetCurrent(context);
// Register methods on target object
SetMethod(context, target, "methodName", MethodCallback);
}
NODE_MODULE_CONTEXT_AWARE_INTERNAL(module_name, Initialize)
Key C++ Subsystems
| Subsystem | Files | Size | Purpose |
|---|---|---|---|
src/crypto/ |
31 | 138K | Full OpenSSL integration: ciphers, hashes, keys, certificates, DH, ECDH, HKDF, PBKDF2, scrypt, sign/verify, X509 |
src/quic/ |
18 | 159K | QUIC transport protocol over UDP using ngtcp2/nghttp3. Experimental. Handles connection state, streams, congestion control, TLS 1.3 handshake |
src/inspector/ |
20 | 39K | Chrome DevTools Protocol implementation: WebSocket transport, V8 inspector bindings, breakpoints, profiling, heap inspection |
src/permission/ |
10 | 19K | Runtime permission checks: filesystem paths, child process, worker threads, native addons, FFI |
src/tracing/ |
6 | 115K | Trace event recording compatible with Chrome tracing format. Categories for V8, Node core, async hooks |
src/large_pages/ |
~2 | Small | Memory mapping of V8 code region to huge pages (2MB) for TLB optimization |
src/dataqueue.h/cc |
2 | — | Internal data queue for blob/stream operations |
FFI (src/) |
2 | 2.6K | Foreign Function Interface binding using libffi |
8.3 JavaScript Standard Library (lib/)
55 top-level modules (898K chars total):
| Module | File | Description |
|---|---|---|
assert |
lib/assert.js |
Assertion testing |
async_hooks |
lib/async_hooks.js |
Async resource lifecycle tracking |
buffer |
lib/buffer.js |
Binary data handling (Buffer, Blob) |
child_process |
lib/child_process.js |
Spawn/exec/fork child processes |
cluster |
lib/cluster.js |
Multi-process server (primary/workers) |
console |
lib/console.js |
Console output (log, warn, error, table) |
crypto |
lib/crypto.js |
Cryptographic operations |
dgram |
lib/dgram.js |
UDP datagram sockets |
diagnostics_channel |
lib/diagnostics_channel.js |
Named publish/subscribe channels for diagnostics |
dns |
lib/dns.js |
DNS resolution (lookup + resolve) |
domain |
lib/domain.js |
Error handling domains (deprecated) |
events |
lib/events.js |
EventEmitter class |
fs |
lib/fs.js |
File system (sync, async, promises, watch) |
http |
lib/http.js |
HTTP/1.1 client and server |
http2 |
lib/http2.js |
HTTP/2 client and server |
https |
lib/https.js |
HTTPS (HTTP over TLS) |
inspector |
lib/inspector.js |
Inspector protocol bindings |
module |
lib/module.js |
Module system access |
net |
lib/net.js |
TCP/IPC networking |
os |
lib/os.js |
Operating system info (cpus, memory, platform) |
path |
lib/path.js |
File path manipulation (posix + win32) |
perf_hooks |
lib/perf_hooks.js |
Performance measurement (marks, measures, observers) |
process |
lib/process.js |
Process info and control |
punycode |
lib/punycode.js |
Unicode/Punycode encoding (deprecated) |
querystring |
lib/querystring.js |
URL query string parsing (legacy, prefer URLSearchParams) |
readline |
lib/readline.js |
Line-by-line input reading |
repl |
lib/repl.js |
Interactive Read-Eval-Print Loop |
sqlite |
lib/sqlite.js |
SQLite database interface |
stream |
lib/stream.js |
Stream base classes and utilities |
string_decoder |
lib/string_decoder.js |
Buffer to string decoding |
sys |
lib/sys.js |
Alias for util (deprecated) |
test |
lib/test.js |
Built-in test runner |
timers |
lib/timers.js |
setTimeout, setInterval, setImmediate |
tls |
lib/tls.js |
TLS/SSL sockets |
trace_events |
lib/trace_events.js |
Trace event management |
tty |
lib/tty.js |
TTY stream handling |
url |
lib/url.js |
URL parsing (WHATWG + legacy) |
util |
lib/util.js |
Utilities (inspect, format, promisify, types) |
v8 |
lib/v8.js |
V8 engine access (heap stats, serialization) |
vm |
lib/vm.js |
Script execution in V8 contexts |
wasi |
lib/wasi.js |
WebAssembly System Interface |
worker_threads |
lib/worker_threads.js |
Multi-threaded JavaScript execution |
zlib |
lib/zlib.js |
Compression (gzip, deflate, brotli) |
8.4 Internal Modules (lib/internal/)
52 internal module directories/files (568K chars) — not accessible via require() from user code. Loaded via internalBinding() or internal require.
| Internal Module | Purpose |
|---|---|
abort_controller |
AbortController/AbortSignal implementation (Web API) |
blob |
Blob and File implementations (Web API) |
buffer |
Buffer internals, FastBuffer (subclass of Uint8Array) |
child_process |
Control class, spawn/exec internals, serialization |
crypto |
Cipher, hash, key, certificate, DH, ECDH, random, scrypt implementations |
encoding |
TextEncoder, TextDecoder (Web API) |
errors |
Error class definitions, error code registry (907 error types) |
event_target |
EventTarget, Event, NodeEventTarget (Web API compatibility) |
file |
File class implementation |
fixed_queue |
High-performance fixed-size circular queue |
freelist |
Object pool pattern for reuse |
fs |
File system internals (promises, streams, watchers, dir, cp, glob) |
heap_utils |
HeapSnapshotStream, heap inspection utilities |
histogram |
Histogram class for latency/performance tracking |
http |
HTTP parser integration, header handling, date cache |
js_stream_socket |
JavaScript-based stream socket implementation |
locks |
Lock, LockManager (Web Locks API) |
mime |
MIMEType, MIMEParams (MIME type parsing) |
modules/cjs/ |
CommonJS loader (Module._resolveFilename, Module._load, Module.wrap) |
modules/esm/ |
ESM loader chain (resolve, load, translate, hooks) |
modules/helpers.js |
Shared module system utilities |
navigator |
Navigator class (limited Web API compatibility) |
process |
Process bootstrap, warning system, nextTick queue |
readline |
Readline internals, completion, history |
socket_list |
SocketAddress management for cluster IPC |
socketaddress |
SocketAddress class |
streams/ |
Stream implementation (readable, writable, duplex, transform, pipeline, compose) |
test_runner/ |
Built-in test runner (test, describe, it, mock, coverage) |
timers |
Timeout, Immediate classes, timer queue management |
tls |
TLS context management, certificate chain handling |
url |
WHATWG URL implementation (wraps ada parser) |
util |
inspect, type checking, promisify, decorators |
v8 |
V8 serialization, deserialization, heap statistics |
vm |
Script, Module, SourceTextModule implementations |
watch_mode |
File watcher for --watch mode |
watchdog |
Execution timeout watchdog (for vm.runInNewContext timeouts) |
webstreams |
Web Streams API (ReadableStream, WritableStream, TransformStream) |
worker |
Worker thread bootstrap, messaging, BroadcastChannel |
8.5 Error System
The error system (lib/internal/errors.js) defines 907 error types organized by category. Every Node.js error has a unique code (e.g., ERR_INVALID_ARG_TYPE) and a corresponding class.
Error Class Hierarchy
Error
├── NodeError (extends Error)
│ ├── ERR_INVALID_ARG_TYPE
│ ├── ERR_INVALID_ARG_VALUE
│ ├── ERR_MISSING_ARGS
│ ├── ERR_OUT_OF_RANGE
│ └── ... (hundreds more)
├── TypeError (NodeTypeError extends TypeError)
│ ├── ERR_INVALID_THIS
│ ├── ERR_INVALID_CALLBACK
│ └── ...
├── RangeError (NodeRangeError extends RangeError)
│ ├── ERR_BUFFER_OUT_OF_BOUNDS
│ ├── ERR_INDEX_OUT_OF_RANGE
│ └── ...
├── SystemError (extends NodeError)
│ ├── errno (libuv error code)
│ ├── syscall (system call name)
│ ├── path (file path, if applicable)
│ └── ... (wraps OS errors)
├── UVException (libuv errors)
│ ├── EACCES, ENOENT, EEXIST, EPERM, ...
│ └── ... (maps libuv errno → Node.js error)
└── AbortError (for AbortSignal cancellations)
Error Categories and Selected Codes
Argument Validation Errors:
| Code | Description |
|---|---|
ERR_INVALID_ARG_TYPE |
Argument of wrong type (most common error) |
ERR_INVALID_ARG_VALUE |
Argument value invalid/out-of-range |
ERR_MISSING_ARGS |
Required argument(s) not provided |
ERR_OUT_OF_RANGE |
Numeric argument outside acceptable range |
ERR_INVALID_CALLBACK |
Callback argument is not a function |
ERR_INVALID_THIS |
Method called with incorrect this context |
ERR_FALSY_VALUE_REJECTION |
Promise rejected with falsy value |
Module System Errors:
| Code | Description |
|---|---|
ERR_MODULE_NOT_FOUND |
ES module not found |
ERR_REQUIRE_ESM |
Attempted require() of ES module |
ERR_REQUIRE_ASYNC_MODULE |
Attempted require() of async ES module |
ERR_UNSUPPORTED_DIR_IMPORT |
Directory import not supported in ESM |
ERR_PACKAGE_PATH_NOT_EXPORTED |
Package subpath not defined in exports |
ERR_PACKAGE_IMPORT_NOT_DEFINED |
Package import not defined in imports map |
ERR_UNKNOWN_FILE_EXTENSION |
Unknown file extension for module loading |
ERR_INVALID_PACKAGE_CONFIG |
Invalid package.json configuration |
ERR_INVALID_MODULE_SPECIFIER |
Invalid module specifier syntax |
File System Errors:
| Code | Description |
|---|---|
ERR_FS_FILE_TOO_LARGE |
File too large for operation |
ERR_FS_INVALID_SYMLINK_TYPE |
Invalid symlink type |
ERR_FS_CP_DIR_TO_NON_DIR |
Cannot copy directory to non-directory |
ERR_FS_CP_EEXIST |
Target already exists (no overwrite) |
ERR_FS_CP_EINVAL |
Invalid copy operation |
ERR_FS_CP_FIFO_PIPE |
Cannot copy FIFO/pipe |
ERR_FS_CP_NON_DIR_TO_DIR |
Cannot copy non-directory to directory |
ERR_FS_CP_SOCKET |
Cannot copy socket |
ERR_FS_CP_SYMLINK_TO_SUBDIRECTORY |
Symlink target is subdirectory of source |
ERR_FS_CP_UNKNOWN |
Unknown file type during copy |
ERR_ACCESS_DENIED |
Permission denied (permission model) |
Network Errors:
| Code | Description |
|---|---|
ERR_SOCKET_ALREADY_BOUND |
Socket already bound to address |
ERR_SOCKET_BAD_BUFFER_SIZE |
Invalid buffer size |
ERR_SOCKET_BAD_PORT |
Port must be ≥ 0 and < 65536 |
ERR_SOCKET_BAD_TYPE |
Invalid socket type |
ERR_SOCKET_BUFFER_SIZE |
Buffer size error |
ERR_SOCKET_CLOSED |
Socket is closed |
ERR_SOCKET_CLOSED_BEFORE_CONNECTION |
Socket closed before connection established |
ERR_SOCKET_CONNECTION_TIMEOUT |
Socket connection timed out |
ERR_SOCKET_DGRAM_IS_CONNECTED |
Datagram socket already connected |
ERR_SOCKET_DGRAM_NOT_CONNECTED |
Datagram socket not connected |
ERR_SOCKET_DGRAM_NOT_RUNNING |
Datagram socket not running |
ERR_SERVER_ALREADY_LISTEN |
Server already listening |
ERR_SERVER_NOT_RUNNING |
Server not running |
HTTP Errors:
| Code | Description |
|---|---|
ERR_HTTP_HEADERS_SENT |
Headers already sent |
ERR_HTTP_INVALID_HEADER_VALUE |
Invalid HTTP header value |
ERR_HTTP_INVALID_STATUS_CODE |
Invalid HTTP status code |
ERR_HTTP_REQUEST_TIMEOUT |
HTTP request timed out |
ERR_HTTP_SOCKET_ENCODING |
Socket encoding error |
ERR_HTTP_TRAILER_INVALID |
Invalid trailer |
ERR_HTTP2_CONNECT_AUTHORITY |
HTTP/2 CONNECT authority missing |
ERR_HTTP2_CONNECT_PATH |
HTTP/2 CONNECT path forbidden |
ERR_HTTP2_CONNECT_SCHEME |
HTTP/2 CONNECT scheme forbidden |
ERR_HTTP2_ERROR |
General HTTP/2 error |
ERR_HTTP2_GOAWAY_SESSION |
HTTP/2 session received GOAWAY |
ERR_HTTP2_HEADERS_AFTER_RESPOND |
HTTP/2 headers after response started |
ERR_HTTP2_HEADERS_SENT |
HTTP/2 headers already sent |
ERR_HTTP2_INVALID_CONNECTION_HEADERS |
HTTP/2 connection-specific headers invalid |
ERR_HTTP2_INVALID_HEADER_VALUE |
Invalid HTTP/2 header value |
ERR_HTTP2_INVALID_INFO_STATUS |
Invalid HTTP/2 informational status |
ERR_HTTP2_INVALID_ORIGIN |
Invalid HTTP/2 origin |
ERR_HTTP2_INVALID_PACKED_SETTINGS_LENGTH |
Invalid packed settings length |
ERR_HTTP2_INVALID_PSEUDOHEADER |
Invalid HTTP/2 pseudo-header |
ERR_HTTP2_INVALID_SESSION |
HTTP/2 session invalid |
ERR_HTTP2_INVALID_SETTING_VALUE |
Invalid HTTP/2 setting value |
ERR_HTTP2_INVALID_STREAM |
Invalid HTTP/2 stream |
ERR_HTTP2_MAX_PENDING_SETTINGS_ACK |
Too many pending HTTP/2 settings |
ERR_HTTP2_NESTED_PUSH |
Nested HTTP/2 push |
ERR_HTTP2_NO_MEM |
HTTP/2 out of memory |
ERR_HTTP2_NO_SOCKET_MANIPULATION |
HTTP/2 socket manipulation forbidden |
ERR_HTTP2_ORIGIN_LENGTH |
HTTP/2 origin length exceeded |
ERR_HTTP2_OUT_OF_STREAMS |
HTTP/2 out of streams |
ERR_HTTP2_PAYLOAD_FORBIDDEN |
HTTP/2 payload forbidden for method |
ERR_HTTP2_PING_CANCEL |
HTTP/2 ping cancelled |
ERR_HTTP2_PING_LENGTH |
HTTP/2 ping length invalid |
ERR_HTTP2_PSEUDOHEADER_NOT_ALLOWED |
HTTP/2 pseudo-header not allowed |
ERR_HTTP2_PUSH_DISABLED |
HTTP/2 push disabled |
ERR_HTTP2_SEND_FILE |
HTTP/2 send file error |
ERR_HTTP2_SEND_FILE_NOSEEK |
HTTP/2 cannot seek file |
ERR_HTTP2_SESSION_ERROR |
HTTP/2 session error |
ERR_HTTP2_SETTINGS_CANCEL |
HTTP/2 settings cancelled |
ERR_HTTP2_SOCKET_BOUND |
HTTP/2 socket already bound |
ERR_HTTP2_SOCKET_UNBOUND |
HTTP/2 socket unbound |
ERR_HTTP2_STATUS_101 |
HTTP/2 status 101 not allowed |
ERR_HTTP2_STATUS_INVALID |
Invalid HTTP/2 status code |
ERR_HTTP2_STREAM_CANCEL |
HTTP/2 stream cancelled |
ERR_HTTP2_STREAM_ERROR |
HTTP/2 stream error |
ERR_HTTP2_STREAM_SELF_DEPENDENCY |
HTTP/2 stream self-dependency |
ERR_HTTP2_TOO_MANY_CUSTOM_SETTINGS |
Too many custom HTTP/2 settings |
ERR_HTTP2_TOO_MANY_INVALID_FRAMES |
Too many invalid HTTP/2 frames |
ERR_HTTP2_TRAILERS_ALREADY_SENT |
HTTP/2 trailers already sent |
ERR_HTTP2_TRAILERS_NOT_READY |
HTTP/2 trailers not ready |
ERR_HTTP2_UNSUPPORTED_PROTOCOL |
Unsupported HTTP/2 protocol |
Crypto Errors:
| Code | Description |
|---|---|
ERR_CRYPTO_CUSTOM_ENGINE_NOT_SUPPORTED |
Custom OpenSSL engine not supported |
ERR_CRYPTO_ECDH_INVALID_FORMAT |
Invalid ECDH format |
ERR_CRYPTO_ECDH_INVALID_PUBLIC_KEY |
Invalid ECDH public key |
ERR_CRYPTO_ENGINE_UNKNOWN |
Unknown crypto engine |
ERR_CRYPTO_FIPS_FORCED |
FIPS mode forced but cannot be enabled |
ERR_CRYPTO_FIPS_UNAVAILABLE |
FIPS not available |
ERR_CRYPTO_HASH_FINALIZED |
Hash already finalized |
ERR_CRYPTO_HASH_UPDATE_FAILED |
Hash update failed |
ERR_CRYPTO_INCOMPATIBLE_KEY |
Incompatible key for operation |
ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS |
Incompatible key options |
ERR_CRYPTO_INITIALIZATION_FAILED |
Crypto initialization failed |
ERR_CRYPTO_INVALID_AUTH_TAG |
Invalid authentication tag |
ERR_CRYPTO_INVALID_COUNTER |
Invalid counter |
ERR_CRYPTO_INVALID_CURVE |
Invalid elliptic curve |
ERR_CRYPTO_INVALID_DIGEST |
Invalid digest algorithm |
ERR_CRYPTO_INVALID_IV |
Invalid initialization vector |
ERR_CRYPTO_INVALID_JWK |
Invalid JSON Web Key |
ERR_CRYPTO_INVALID_KEY_OBJECT_TYPE |
Invalid key object type |
ERR_CRYPTO_INVALID_KEYLEN |
Invalid key length |
ERR_CRYPTO_INVALID_KEYPAIR |
Invalid key pair |
ERR_CRYPTO_INVALID_MESSAGELEN |
Invalid message length |
ERR_CRYPTO_INVALID_SCRYPT_PARAMS |
Invalid scrypt parameters |
ERR_CRYPTO_INVALID_STATE |
Invalid crypto state |
ERR_CRYPTO_INVALID_TAG_LENGTH |
Invalid tag length |
ERR_CRYPTO_JOB_INIT_FAILED |
Crypto job initialization failed |
ERR_CRYPTO_JWK_UNSUPPORTED_CURVE |
Unsupported JWK curve |
ERR_CRYPTO_JWK_UNSUPPORTED_KEY_TYPE |
Unsupported JWK key type |
ERR_CRYPTO_OPERATION_FAILED |
Crypto operation failed |
ERR_CRYPTO_PBKDF2_ERROR |
PBKDF2 error |
ERR_CRYPTO_SCRYPT_INVALID_PARAMETER |
Invalid scrypt parameter |
ERR_CRYPTO_SCRYPT_NOT_SUPPORTED |
Scrypt not supported |
ERR_CRYPTO_SIGN_KEY_REQUIRED |
Sign key required |
ERR_CRYPTO_TIMING_SAFE_EQUAL_LENGTH |
Buffers must be same length for timingSafeEqual |
ERR_CRYPTO_UNKNOWN_CIPHER |
Unknown cipher algorithm |
ERR_CRYPTO_UNKNOWN_DH_GROUP |
Unknown DH group |
ERR_CRYPTO_UNSUPPORTED_OPERATION |
Unsupported crypto operation |
Stream Errors:
| Code | Description |
|---|---|
ERR_STREAM_ALREADY_FINISHED |
Stream write after end |
ERR_STREAM_CANNOT_PIPE |
Cannot pipe from this stream |
ERR_STREAM_DESTROYED |
Stream was destroyed |
ERR_STREAM_NULL_VALUES |
Null values cannot be written to stream |
ERR_STREAM_PREMATURE_CLOSE |
Stream closed prematurely |
ERR_STREAM_PUSH_AFTER_EOF |
Push after EOF |
ERR_STREAM_UNSHIFT_AFTER_END_EVENT |
Unshift after end event |
ERR_STREAM_WRAP |
Stream wrapping error |
ERR_STREAM_WRITE_AFTER_END |
Write after end |
Worker Thread Errors:
| Code | Description |
|---|---|
ERR_WORKER_INIT_FAILED |
Worker initialization failed |
ERR_WORKER_INVALID_EXEC_ARGV |
Invalid worker exec argv |
ERR_WORKER_NOT_RUNNING |
Worker is not running |
ERR_WORKER_OUT_OF_MEMORY |
Worker ran out of memory |
ERR_WORKER_PATH |
Invalid worker file path |
ERR_WORKER_UNSERIALIZABLE_ERROR |
Error cannot be serialized for transfer |
ERR_WORKER_UNSUPPORTED_EXTENSION |
Unsupported file extension for worker |
ERR_WORKER_UNSUPPORTED_OPERATION |
Unsupported operation in worker |
TLS/SSL Errors:
| Code | Description |
|---|---|
ERR_TLS_CERT_ALTNAME_FORMAT |
Invalid certificate altname format |
ERR_TLS_CERT_ALTNAME_INVALID |
Certificate hostname mismatch |
ERR_TLS_DH_PARAM_SIZE |
DH parameter size too small |
ERR_TLS_HANDSHAKE_TIMEOUT |
TLS handshake timed out |
ERR_TLS_INVALID_CONTEXT |
Invalid TLS context |
ERR_TLS_INVALID_PROTOCOL_METHOD |
Invalid TLS protocol method |
ERR_TLS_INVALID_PROTOCOL_VERSION |
Invalid TLS protocol version |
ERR_TLS_INVALID_STATE |
Invalid TLS state |
ERR_TLS_PROTOCOL_VERSION_CONFLICT |
TLS protocol version conflict |
ERR_TLS_PSK_SET_IDENTITY_HINT_FAILED |
Failed to set PSK identity hint |
ERR_TLS_RENEGOTIATION_DISABLED |
TLS renegotiation disabled |
ERR_TLS_REQUIRED_SERVER_NAME |
Server name required for TLS |
ERR_TLS_SESSION_ATTACK |
TLS session renegotiation attack detected |
ERR_TLS_SNI_FROM_SERVER |
SNI from server (unexpected) |
Encoding Errors:
| Code | Description |
|---|---|
ERR_ENCODING_INVALID_ENCODED_DATA |
Invalid encoded data |
ERR_ENCODING_NOT_SUPPORTED |
Encoding not supported |
ERR_UNKNOWN_ENCODING |
Unknown encoding name |
VM (Virtual Machine) Errors:
| Code | Description |
|---|---|
ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING |
Dynamic import callback not set |
ERR_VM_MODULE_ALREADY_LINKED |
Module already linked |
ERR_VM_MODULE_CACHED_DATA_REJECTED |
Cached data rejected |
ERR_VM_MODULE_CANNOT_CREATE_CACHED_DATA |
Cannot create cached data |
ERR_VM_MODULE_DIFFERENT_CONTEXT |
Module from different context |
ERR_VM_MODULE_LINK_FAILURE |
Module link failure |
ERR_VM_MODULE_LINKING_ERRORED |
Module linking errored |
ERR_VM_MODULE_NOT_MODULE |
Not a module |
ERR_VM_MODULE_STATUS |
Invalid module status |
Assertion and Validation Errors:
| Code | Description |
|---|---|
ERR_ASSERTION |
Assertion failed |
ERR_AMBIGUOUS_ARGUMENT |
Ambiguous argument |
ERR_INCOMPATIBLE_OPTION_PAIR |
Incompatible option pair |
ERR_INVALID_RETURN_PROPERTY |
Invalid return property |
ERR_INVALID_RETURN_PROPERTY_VALUE |
Invalid return property value |
ERR_INVALID_RETURN_VALUE |
Invalid return value |
ERR_INVALID_STATE |
Invalid state for operation |
ERR_INVALID_URL |
Invalid URL |
ERR_INVALID_URL_SCHEME |
Invalid URL scheme |
Permission Model Errors:
| Code | Description |
|---|---|
ERR_ACCESS_DENIED |
Operation denied by permission model |
ERR_MANIFEST_ASSERT_INTEGRITY |
Module integrity check failed (policy) |
ERR_MANIFEST_DEPENDENCY_MISSING |
Manifest dependency missing |
ERR_MANIFEST_INTEGRITY_MISMATCH |
Manifest integrity mismatch |
ERR_MANIFEST_INVALID_RESOURCE_FIELD |
Invalid manifest resource field |
ERR_MANIFEST_INVALID_SPECIFIER |
Invalid manifest specifier |
ERR_MANIFEST_PARSE_POLICY |
Cannot parse policy manifest |
ERR_MANIFEST_TDZ |
Manifest temporal dead zone |
ERR_MANIFEST_UNKNOWN_ONERROR |
Unknown manifest onError action |
Miscellaneous Errors:
| Code | Description |
|---|---|
ERR_BUFFER_CONTEXT_NOT_AVAILABLE |
Buffer context not available |
ERR_BUFFER_OUT_OF_BOUNDS |
Buffer access out of bounds |
ERR_BUFFER_TOO_LARGE |
Buffer exceeds maximum length |
ERR_CANNOT_WATCH_SIGINT |
Cannot watch SIGINT |
ERR_CHILD_CLOSED_BEFORE_REPLY |
Child closed before reply |
ERR_CHILD_PROCESS_IPC_REQUIRED |
IPC channel required |
ERR_CHILD_PROCESS_STDIO_MAXBUFFER |
MaxBuffer exceeded |
ERR_CONSOLE_WRITABLE_STREAM |
Console writable stream error |
ERR_CONSTRUCT_CALL_INVALID |
Constructor call invalid |
ERR_CONSTRUCT_CALL_REQUIRED |
Constructor call required |
ERR_CONTEXT_NOT_INITIALIZED |
Context not initialized |
ERR_DEBUGGER_ERROR |
Debugger error |
ERR_DEBUGGER_STARTUP_ERROR |
Debugger startup error |
ERR_DIR_CLOSED |
Directory handle closed |
ERR_DIR_CONCURRENT_OPERATION |
Concurrent directory operation |
ERR_DNS_SET_SERVERS_FAILED |
DNS set servers failed |
ERR_DOMAIN_CALLBACK_NOT_AVAILABLE |
Domain callback not available |
ERR_DOMAIN_CANNOT_SET_UNCAUGHT_EXCEPTION_CAPTURE |
Domain conflict with uncaughtException capture |
ERR_DUPLICATE_STARTUP_SNAPSHOT_MAIN_FUNCTION |
Duplicate snapshot main function |
ERR_EVAL_ESM_CANNOT_PRINT |
Cannot print ESM eval result |
ERR_EVENT_RECURSION |
Event recursion detected |
ERR_FEATURE_UNAVAILABLE_ON_PLATFORM |
Feature unavailable on this platform |
ERR_ILLEGAL_CONSTRUCTOR |
Constructor is not callable |
ERR_IMPORT_ASSERTION_TYPE_FAILED |
Import assertion type check failed |
ERR_IMPORT_ASSERTION_TYPE_MISSING |
Import assertion type missing |
ERR_IMPORT_ASSERTION_TYPE_UNSUPPORTED |
Unsupported import assertion type |
ERR_IMPORT_ATTRIBUTE_MISSING |
Import attribute missing |
ERR_IMPORT_ATTRIBUTE_TYPE_INCOMPATIBLE |
Import attribute type incompatible |
ERR_IMPORT_ATTRIBUTE_UNSUPPORTED |
Unsupported import attribute |
ERR_INPUT_TYPE_NOT_ALLOWED |
Input type not allowed |
ERR_INSPECTOR_ALREADY_ACTIVATED |
Inspector already activated |
ERR_INSPECTOR_ALREADY_CONNECTED |
Inspector already connected |
ERR_INSPECTOR_CLOSED |
Inspector session closed |
ERR_INSPECTOR_COMMAND |
Inspector command error |
ERR_INSPECTOR_NOT_ACTIVE |
Inspector not active |
ERR_INSPECTOR_NOT_AVAILABLE |
Inspector not available |
ERR_INSPECTOR_NOT_CONNECTED |
Inspector not connected |
ERR_INSPECTOR_NOT_WORKER |
Inspector not in worker |
ERR_INTERNAL_ASSERTION |
Internal assertion (Node.js bug) |
ERR_IPC_CHANNEL_CLOSED |
IPC channel closed |
ERR_IPC_DISCONNECTED |
IPC disconnected |
ERR_IPC_ONE_PIPE |
Only one IPC pipe allowed |
ERR_IPC_SYNC_FORK |
Synchronous fork with IPC |
ERR_LOADER_CHAIN_INCOMPLETE |
Loader chain incomplete |
ERR_METHOD_NOT_IMPLEMENTED |
Method not implemented |
ERR_MISSING_OPTION |
Required option missing |
ERR_MISSING_TRANSFERABLE_IN_TRANSFER_LIST |
Missing transferable in transfer list |
ERR_MULTIPLE_CALLBACK |
Callback called multiple times |
ERR_NAPI_CONS_FUNCTION |
N-API constructor function error |
ERR_NAPI_CONS_PROTOTYPE_OBJECT |
N-API constructor prototype error |
ERR_NAPI_INVALID_DATAVIEW_ARGS |
Invalid N-API DataView arguments |
ERR_NAPI_INVALID_TYPEDARRAY_ALIGNMENT |
Invalid N-API TypedArray alignment |
ERR_NAPI_INVALID_TYPEDARRAY_LENGTH |
Invalid N-API TypedArray length |
ERR_NAPI_TSFN_CALL_JS |
N-API TSFN call JS error |
ERR_NAPI_TSFN_GET_UNDEFINED |
N-API TSFN get undefined error |
ERR_NAPI_TSFN_START_IDLE_LOOP |
N-API TSFN idle loop start error |
ERR_NAPI_TSFN_STOP_IDLE_LOOP |
N-API TSFN idle loop stop error |
ERR_NOT_BUILDING_SNAPSHOT |
Not building snapshot |
ERR_NOT_IN_SINGLE_EXECUTABLE_APPLICATION |
Not in a SEA |
ERR_NOT_SUPPORTED_IN_SNAPSHOT |
Not supported in snapshot |
ERR_OPERATION_FAILED |
Operation failed |
ERR_OUTOFMEMORY |
Out of memory |
ERR_PARSE_ARGS_INVALID_OPTION_VALUE |
Invalid parseArgs option value |
ERR_PARSE_ARGS_UNEXPECTED_POSITIONAL |
Unexpected positional argument |
ERR_PARSE_ARGS_UNKNOWN_OPTION |
Unknown parseArgs option |
ERR_PERFORMANCE_INVALID_TIMESTAMP |
Invalid performance timestamp |
ERR_PERFORMANCE_MEASURE_INVALID_OPTIONS |
Invalid performance measure options |
ERR_QUIC_CONNECTION_FAILED |
QUIC connection failed |
ERR_QUIC_ENDPOINT_CLOSED |
QUIC endpoint closed |
ERR_QUIC_OPEN_STREAM_FAILED |
QUIC stream open failed |
ERR_QUIC_TRANSPORT_ERROR |
QUIC transport error |
ERR_SCRIPT_EXECUTION_INTERRUPTED |
Script execution interrupted |
ERR_SCRIPT_EXECUTION_TIMEOUT |
Script execution timed out |
ERR_SINGLE_EXECUTABLE_APPLICATION_ASSET_NOT_FOUND |
SEA asset not found |
ERR_SQLITE_ERROR |
SQLite error |
ERR_TEST_FAILURE |
Test failure |
ERR_UNAVAILABLE_DURING_EXIT |
Unavailable during process exit |
ERR_UNCAUGHT_EXCEPTION_CAPTURE_ALREADY_SET |
Uncaught exception capture already set |
ERR_UNESCAPED_CHARACTERS |
Unescaped characters in string |
ERR_UNHANDLED_REJECTION |
Unhandled promise rejection |
ERR_UNKNOWN_BUILTIN_MODULE |
Unknown built-in module |
ERR_UNKNOWN_CREDENTIAL |
Unknown credential |
ERR_UNKNOWN_SIGNAL |
Unknown signal name |
ERR_USE_AFTER_CLOSE |
Use after close |
ERR_VALID_PERFORMANCE_ENTRY_TYPE |
Valid performance entry type required |
ERR_WASI_ALREADY_STARTED |
WASI already started |
ERR_WASI_NOT_STARTED |
WASI not started |
ERR_ZLIB_INITIALIZATION_FAILED |
Zlib initialization failed |
8.6 Key Classes
| Class | Module | Description |
|---|---|---|
AbortController |
lib/internal/abort_controller.js |
Web API: control abort signals for cancellable operations |
AbortSignal |
lib/internal/abort_controller.js |
Web API: signal for aborting async operations |
Blob |
lib/internal/blob.js |
Web API: immutable raw data container |
File |
lib/internal/file.js |
Web API: file metadata + blob data |
BlockList |
lib/net.js |
IP address block list for access control |
FastBuffer |
lib/internal/buffer.js |
Optimized Buffer subclass of Uint8Array |
TextEncoder |
lib/internal/encoding.js |
Web API: string → UTF-8 bytes |
TextDecoder |
lib/internal/encoding.js |
Web API: bytes → string (multiple encodings) |
URL |
lib/internal/url.js |
WHATWG URL parser (wraps ada C++ library) |
URLSearchParams |
lib/internal/url.js |
URL query parameter manipulation |
Worker |
lib/internal/worker.js |
Worker thread management |
Event |
lib/internal/event_target.js |
Web API: base event class |
EventTarget |
lib/internal/event_target.js |
Web API: event dispatch target |
NodeEventTarget |
lib/internal/event_target.js |
Hybrid EventTarget + EventEmitter |
Histogram |
lib/internal/histogram.js |
Statistical histogram (percentiles, min, max, mean) |
MIMEType |
lib/internal/mime.js |
MIME type parsing and manipulation |
MIMEParams |
lib/internal/mime.js |
MIME type parameters |
Navigator |
lib/internal/navigator.js |
Web API: limited navigator (hardwareConc, language) |
SocketAddress |
lib/internal/socketaddress.js |
IP address + port encapsulation |
Timeout |
lib/internal/timers.js |
setTimeout/setInterval handle |
Immediate |
lib/internal/timers.js |
setImmediate handle |
Lock |
lib/internal/locks.js |
Web Locks API: named lock |
LockManager |
lib/internal/locks.js |
Web Locks API: lock coordination |
HeapSnapshotStream |
lib/internal/heap_utils.js |
Readable stream of V8 heap snapshot data |
Control |
lib/internal/child_process.js |
Internal child process control |
ReadableStream |
lib/internal/webstreams/ |
Web Streams API: readable stream |
WritableStream |
lib/internal/webstreams/ |
Web Streams API: writable stream |
TransformStream |
lib/internal/webstreams/ |
Web Streams API: transform stream |
8.7 Code Patterns and Conventions
Primordials
Node.js protects against prototype pollution by capturing built-in functions at startup:
// lib/internal/per_context/primordials.js captures everything:
const {
ArrayPrototypeMap,
ObjectDefineProperty,
StringPrototypeSlice,
PromisePrototypeThen,
SafeMap,
SafeSet,
SafeWeakMap,
} = primordials;
// Usage in internal modules — never call Array.prototype.map directly
const result = ArrayPrototypeMap(items, transform);
This prevents user code from breaking Node.js internals by modifying Array.prototype.map, Object.keys, etc.
Internal Bindings
C++ modules are exposed to JavaScript via internalBinding():
// In lib/internal/crypto/hash.js
const { Hash: _Hash } = internalBinding('crypto');
// _Hash is a C++ class from src/crypto/crypto_hash.cc
Public modules use process.binding() (deprecated) or internalBinding() (internal only, not accessible from user code).
Lazy Loading
Expensive modules are loaded on first use:
let crypto;
function getCrypto() {
if (crypto === undefined) {
crypto = require('crypto');
}
return crypto;
}
Validators
lib/internal/validators.js provides standardized argument validation:
const {
validateFunction,
validateInteger,
validateObject,
validateString,
validateBoolean,
validateAbortSignal,
validateBuffer,
validateEncoding,
validatePort,
} = require('internal/validators');
// Usage
function myFunction(path, options) {
validateString(path, 'path');
validateObject(options, 'options');
validateInteger(options.timeout, 'options.timeout', 0);
}
8.8 Testing Infrastructure
The test suite contains 4,000+ test files organized by category:
| Category | Directory | File Count | Description |
|---|---|---|---|
| parallel | test/parallel/ |
3,929 | Standard tests that run in parallel |
| sequential | test/sequential/ |
111 | Tests requiring exclusive execution |
| pseudo-tty | test/pseudo-tty/ |
40 | Tests requiring a pseudo-terminal |
| async-hooks | test/async-hooks/ |
98 | Async hooks lifecycle tests |
| es-module | test/es-module/ |
97 | ECMAScript module system tests |
| pummel | test/pummel/ |
64 | Stress tests (heavy I/O, memory) |
| embedding | test/embedding/ |
14 | Node.js embedding API tests |
| addons | test/addons/ |
~100+ | C++ addon tests (old API) |
| node-api | test/node-api/ |
~100+ | Node-API (N-API) native addon tests |
| sea | test/sea/ |
37 | Single Executable Application tests |
| wasi | test/wasi/ |
27 | WebAssembly System Interface tests |
| ffi | test/ffi/ |
10 | Foreign Function Interface tests |
| known_issues | test/known_issues/ |
24 | Tests for known unfixed bugs |
| cctest | test/cctest/ |
varies | C++ unit tests (googletest) |
| wasm | test/wasm/ |
varies | WebAssembly tests |
| internet | test/internet/ |
varies | Tests requiring internet access |
| tick-processor | test/tick-processor/ |
varies | V8 tick processor tests |
| message | test/message/ |
varies | Expected output message tests |
| fixtures | test/fixtures/ |
varies | Shared test fixtures and data |
| common | test/common/ |
varies | Shared test utilities and helpers |
Running Tests
# Run all tests
make test
# Run parallel tests only
make test-parallel
# Run a specific test
python3 tools/test.py test/parallel/test-http-server.js
# Run with verbose output
python3 tools/test.py -v test/parallel/test-http-server.js
# Run linting
make lint
make lint-js # JavaScript only
make lint-cpp # C++ only
make lint-md # Markdown only
# Run C++ tests
make cctest
# Run with code coverage
make coverage
# Run benchmarks
make bench
8.9 Contributing — Build and Test Workflow
# 1. Clone and build
git clone https://github.com/nodejs/node.git
cd node
./configure --ninja
ninja -C out/Release -j$(nproc)
# 2. Run tests
make test
# 3. After making changes, run affected tests
python3 tools/test.py test/parallel/test-your-feature.js
# 4. Lint
make lint
# 5. Generate documentation
make doc
9. Integration Points
9.1 Node-API (N-API)
Node-API is the stable ABI for building native addons that work across Node.js versions without recompilation:
// addon.c
#include <node_api.h>
napi_value MyFunction(napi_env env, napi_callback_info info) {
napi_value result;
napi_create_string_utf8(env, "hello from C", NAPI_AUTO_LENGTH, &result);
return result;
}
napi_value Init(napi_env env, napi_value exports) {
napi_property_descriptor desc = {
"myFunction", NULL, MyFunction, NULL, NULL, NULL, napi_default, NULL
};
napi_define_properties(env, exports, 1, &desc);
return exports;
}
NAPI_MODULE(NODE_GYP_MODULE_NAME, Init)
// Usage
const addon = require('./build/Release/addon.node');
console.log(addon.myFunction()); // "hello from C"
Node-API tests live in test/node-api/ and exercise all API surface areas. The API is versioned (currently up to version 9+), with each version adding new functions while maintaining backward compatibility.
9.2 V8 Embedding API
Node.js can be embedded in other C++ applications:
#include "node.h"
#include "uv.h"
int main(int argc, char* argv[]) {
// Initialize Node.js
std::vector<std::string> args(argv, argv + argc);
std::unique_ptr<node::InitializationResult> result =
node::InitializeOncePerProcess(args);
// Create isolate and environment
node::EmbedderSnapshotData::Pointer snapshot;
v8::Isolate* isolate = node::NewIsolate(
node::CreateArrayBufferAllocator(), &loop, platform.get());
// Run Node.js event loop
node::LoadEnvironment(env, "const http = require('http');"
"http.createServer((req, res) => {"
" res.end('embedded');"
"}).listen(3000);");
// Spin the event loop
node::SpinEventLoop(env).FromJust();
// Cleanup
node::Stop(env);
return 0;
}
Embedding tests are in test/embedding/ (14 test files).
9.3 Foreign Function Interface (FFI)
Experimental FFI allows calling native shared library functions without compiling a native addon:
// Experimental — requires --experimental-permission and --allow-ffi
import { dlopen, FFIType } from 'node:ffi';
const lib = dlopen('libm.so.6', {
ceil: {
args: [FFIType.f64],
returns: FFIType.f64,
},
});
console.log(lib.symbols.ceil(1.2)); // 2
The FFI implementation is minimal (2 files, 2.6K chars in src/) and wraps libffi. Tests are in test/ffi/ (10 files).
9.4 WASI (WebAssembly System Interface)
WASI provides a sandboxed system interface for WebAssembly modules:
import { readFile } from 'node:fs/promises';
import { WASI } from 'node:wasi';
const wasi = new WASI({
version: 'preview1',
args: process.argv,
env: process.env,
preopens: {
'/sandbox': '/tmp/wasi-sandbox'
}
});
const wasm = await WebAssembly.compile(await readFile('./module.wasm'));
const instance = await WebAssembly.instantiate(wasm, wasi.getImportObject());
wasi.start(instance);
WASI tests are in test/wasi/ (27 files). The implementation wraps uvwasi (in deps).
9.5 Inspector Protocol (CDP)
The Chrome DevTools Protocol enables programmatic debugging, profiling, and automation:
import inspector from 'node:inspector/promises';
const session = new inspector.Session();
session.connect();
// Take heap snapshot
await session.post('HeapProfiler.takeHeapSnapshot');
// Enable CPU profiler
await session.post('Profiler.enable');
await session.post('Profiler.start');
// ... run workload ...
const { profile } = await session.post('Profiler.stop');
// Evaluate expressions
const { result } = await session.post('Runtime.evaluate', {
expression: 'process.memoryUsage()'
});
session.disconnect();
The inspector can also be accessed over WebSocket (port 9229 by default) for remote debugging with Chrome DevTools, VS Code, or any CDP-compatible client.
9.6 Diagnostics Channel
Named publish/subscribe channels for instrumenting Node.js core and third-party modules:
import diagnostics_channel from 'node:diagnostics_channel';
// Subscribe to HTTP request events
const channel = diagnostics_channel.channel('http.client.request.start');
channel.subscribe((message) => {
console.log('HTTP request:', message.request.method, message.request.path);
});
// Built-in channels include:
// http.client.request.start / .error
// http.client.response.finish
// http.server.request.start / .error
// http.server.response.finish
// net.client.socket / net.server.socket
// worker_threads (various)
// module.require.start / .end
// module.import.start / .end
Note
Diagnostics channels have near-zero overhead when no subscribers are attached. They are the recommended way to instrument Node.js applications for monitoring and tracing, replacing monkey-patching approaches used by older APM tools.