A Deep Dive into Hidden Threads in Node.js
When people say “JavaScript is single-threaded,” they’re mostly right — but if you’re working with Node.js, the full story is far more interesting.
Under the hood, Node.js is a multithreaded runtime. Even though your JavaScript code runs on a single thread, Node itself uses multiple threads behind the scenes to keep things fast, efficient, and non-blocking. This article explores how those threads work, what role they play, and how they interact with your code.
Why Does Node.js Need Hidden Threads?
JavaScript was originally designed to run in browsers — environments that operate on a single thread where one task runs at a time. But server-side applications often involve I/O operations like reading files, querying databases, or making HTTP requests. If these were executed synchronously, they would block the main thread and significantly degrade performance.
To solve this, Node.js leverages libuv, a C-based library that provides an event loop and thread pool, enabling non-blocking I/O operations.
The Thread Breakdown
A typical Node.js process includes seven threads by default:
Thread Type Count Purpose Main thread 1 Executes your JavaScript code libuv worker threads 4 Handles asynchronous I/O (file system, DNS, etc.) V8 internal threads 2 Manages garbage collection and JIT compilation
Let’s break down the responsibilities of each.
1. The Main Thread
This is where your JavaScript code executes — including variables, functions, and event listeners.
Limitations:
- Only one operation executes at a time.
- Blocking operations (like CPU-intensive computations) freeze the event loop, stalling the entire application.
2. The libuv Thread Pool
libuv creates a thread pool with four worker threads by default to handle expensive operations outside the main thread.
Tasks delegated to libuv include:
- File system access (e.g.,
fs.readFile) - DNS lookups (non-cached)
- Compression, encryption, and hashing operations
Execution flow for a file read:
- The main thread calls
fs.readFile(). - libuv assigns the task to a worker thread.
- The worker completes the operation.
- The callback is pushed onto the event loop.
- Once the main thread is idle, the callback is executed.
While the callback runs on the main thread, the I/O operation itself happens in a worker thread, ensuring non-blocking behavior.
3. V8 Internal Threads
Node.js uses the V8 JavaScript engine, which maintains two internal threads:
- Garbage Collector: Frees up unused memory.
- JIT Compiler: Converts frequently used code into machine-level instructions for better performance.
These internal threads optimize execution without affecting your main thread.
Observing the Hidden Threads
To see these threads in action:
- Start a background Node process:
node process.js &2. Check its threads using:
top -H -p <PID>Output:
Threads: 7 total, 1 running, 6 sleeping
PID %CPU COMMAND
9933 99.9 node <-- main thread
9934 0.0 node <-- background thread
...This confirms that a Node.js process spawns multiple threads under the hood.
CPU-Bound Work: The Catch
While hidden threads handle I/O very efficiently, they do not help with CPU-intensive operations such as:
- JSON parsing of large datasets
- Cryptographic calculations
- Image or video processing
These operations execute on the main thread and block the event loop, impacting performance.
Solutions:
- Use the
worker_threadsmodule for CPU-heavy tasks. - Use the
child_processmodule for process-level isolation. - Offload tasks to external services or message queues.
Best Practices and Tuning Tips
- Avoid CPU-intensive logic on the main thread.
- Use
worker_threadswhen concurrency is needed. - For memory isolation or high parallelism, prefer spawning new processes.
- You can increase the libuv thread pool (up to 128) if your application is I/O intensive:
UV_THREADPOOL_SIZE=8 node app.jsConclusion
Although JavaScript runs in a single thread, Node.js is designed with concurrency in mind. Thanks to libuv and V8, Node offloads time-consuming operations to background threads and keeps your applications responsive and efficient.
