Architectural Layers
V8 JavaScript Engine
The foundation of Node.js is Google’s V8 engine, which compiles JavaScript to native machine code using just-in-time (JIT) compilation. V8 provides the JavaScript runtime environment, garbage collection, and the execution context for all JavaScript code.
libuv Event Loop
libuv is a multi-platform C library that provides asynchronous I/O operations. It implements the event loop, thread pool, and handles file system operations, network I/O, timers, and child processes.
C++ Bindings Layer
Node.js core is written in C++ and provides bindings between JavaScript and low-level system APIs. This layer exposes native functionality to JavaScript through the N-API and internal bindings.
V8 Engine Integration
Node.js embeds the V8 JavaScript engine to execute JavaScript code. The integration happens through several key components:Isolate and Context
Every Node.js process creates a V8 Isolate, which represents an isolated instance of the V8 engine with its own heap. Within an isolate, contexts provide separate JavaScript execution environments.The V8 isolate is the fundamental unit of isolation in Node.js. Worker threads each get their own isolate, ensuring complete memory isolation between threads.
Just-In-Time Compilation
V8 uses multiple compilation tiers:- Ignition: The interpreter for initial execution
- TurboFan: The optimizing compiler for hot code paths
- Sparkplug: A fast non-optimizing compiler (intermediate tier)
libuv and the C++ Layer
The libuv library provides the asynchronous I/O capabilities that make Node.js non-blocking. It’s responsible for:Event Loop Management
The event loop is implemented entirely in libuv. Node.js initializes the loop during startup:Thread Pool
libuv maintains a thread pool (default size: 4 threads) for operations that don’t have native async APIs:- File system operations
- DNS lookups (getaddrinfo, getnameinfo)
- Certain crypto operations
- User-land code via
crypto.pbkdf2,zlib, etc.
Platform Abstractions
libuv provides a consistent API across platforms:- Linux/Unix: Uses epoll, kqueue for I/O polling
- Windows: Uses IOCP (I/O Completion Ports)
- File watchers: inotify (Linux), kqueue (BSD), FSEvents (macOS), ReadDirectoryChangesW (Windows)
Native Modules and Addons
Node.js supports extending functionality through native C++ addons.Internal Bindings
Node.js core uses internal bindings to expose C++ functionality to JavaScript:Internal bindings are private APIs not exposed to userland. They provide the bridge between JavaScript core modules and C++ implementations.
N-API (Node-API)
N-API is the stable API for building native addons, designed to be ABI-stable across Node.js versions:Addon Architecture
Native Addon Loading Process
Native Addon Loading Process
- Module loads via
require('addon.node') - Node.js calls
dlopen()to load the shared library - Addon’s
NAPI_MODULE_INITmacro registers the module - Node.js creates JavaScript wrapper around C++ exports
- Module becomes available to JavaScript code
Environment and Realm
Node.js uses the concept of Environment and Realm to manage execution contexts:Environment (env.h)
The Environment class represents the state of a Node.js instance:
- Reference to the V8 isolate
- libuv event loop
- Async hooks state
- Module loading state
- Performance timing data
Realm (node_realm.h)
Realms represent separate JavaScript execution contexts:
Process Lifecycle
The Node.js process goes through several phases:Initialization
- Initialize V8 platform and isolate
- Set up libuv event loop
- Load internal bindings
- Initialize environment
Bootstrap
- Load pre-execution modules
- Set up
processobject - Initialize module system
- Load user script
Memory Management
Node.js uses V8’s garbage collector with additional memory tracking:Heap Structure
- New Space: Young generation (short-lived objects)
- Old Space: Long-lived objects
- Large Object Space: Objects larger than 512KB
- Code Space: JIT compiled code
External Memory
Node.js tracks external memory (Buffers, etc.) and reports it to V8:Platform-Specific Implementations
Node.js handles platform differences through:- Conditional compilation:
#ifdefblocks in C++ code - Platform modules: Windows vs Unix implementations
- libuv abstractions: Unified API across platforms
src/node_platform.cc- Threading and task schedulingsrc/node_file.cc- File system operations with platform-specific syscalls
Related Topics
- Event Loop - Deep dive into event loop phases
- Modules - Module loading and resolution
- Async Programming - Asynchronous patterns in Node.js