What Node Actually Is
The runtime, not the language: where Node came from, the parts it is built from (V8, libuv, OpenSSL, zlib, c-ares, llhttp and the bindings that join them), how its release lines work, how it compares with Deno and Bun, and how it is built from source.
The 2009 origin and the C10K problem
Node exists because of one engineering observation: most server time is spent waiting on IO, and threads are an expensive way to wait. A thread-per-connection server holds a stack (often 1 to 8 MB of reserved address space) and a kernel scheduling entry for every idle connection. An event loop holds a few hundred bytes of state per connection and asks the kernel which ones are ready.
// the C10K idea in eight lines: one thread, many sockets, nobody blocks
import net from 'node:net';
let open = 0;
net.createServer(sock => {
open++;
sock.on('data', d => sock.write(d)); // echo, never blocking
sock.on('close', () => open--);
}).listen(7000);
setInterval(() => console.log('open connections', open, 'rss MB', (process.memoryUsage().rss / 1e6).toFixed(1)), 2000);net.connect in another process) and watch RSS. Memory grows by kilobytes per connection, not megabytes. That is the whole original pitch.The architecture: V8, libuv and the C libraries
| layer | where in the repo | what it does |
|---|---|---|
| your code + lib/ | lib/*.js | the standard library, written mostly in JavaScript |
| bindings | src/*.cc | C++ that exposes native functionality to lib/ via internalBinding() |
| V8 | deps/v8 | parsing, compiling, executing JS, heap and GC |
| libuv | deps/uv | event loop, non-blocking sockets, timers, threadpool, signals, child processes |
| OpenSSL | deps/openssl | TLS, hashing, ciphers, key generation |
| zlib, brotli | deps/zlib, deps/brotli | compression streams |
| c-ares | deps/cares | asynchronous DNS for dns.resolve* (not dns.lookup, see part 2) |
| llhttp, nghttp2, ngtcp2 | deps/llhttp, … | HTTP/1.1 parsing, HTTP/2 framing, QUIC work |
| ICU | deps/icu-small | Intl, Unicode normalisation, time zones |
// what your Node was built with
console.log(process.versions); // { node, v8, uv, openssl, zlib, ares, llhttp, nghttp2, icu, ... }
console.log(process.config.variables.node_shared_openssl); // vendored or system OpenSSL?Release lines, governance, and Node vs Deno vs Bun
Node ships a new major every six months. Even-numbered majors become LTS in October: about 6 months as Current, then roughly 30 months of Active and Maintenance LTS. Odd majors never become LTS. Production should run Active LTS, and plan the upgrade before Maintenance ends.
| Node | Deno | Bun | |
|---|---|---|---|
| engine | V8 | V8 | JavaScriptCore |
| runtime language | C++ (+ JS in lib/) | Rust (Tokio) | Zig |
| event loop | libuv | Tokio | custom, io_uring/kqueue |
| security model | opt-in permission model | deny by default, flags to allow | none built in |
| TypeScript | type stripping (erasable syntax) | built in | built in transpiler |
| npm compatibility | native | npm: specifiers, node: modules | high, Node APIs reimplemented |
The architectural point: Deno and Bun replace libuv and the C++ glue, so the event loop details in part 3 differ, while V8 knowledge (part 2) transfers to Deno but not to Bun.
# building Node from source (what a build produces) git clone https://github.com/nodejs/node && cd node ./configure # Python script: detects the platform, writes config.gypi make -j8 # GYP generates Makefiles; outputs out/Release/node ./out/Release/node -p process.versions.node # configure flags worth knowing: --debug, --without-intl, --shared-openssl, --enable-lto