Node.js is single-threaded for your JavaScript code, but under the hood it uses multiple threads via libuv for I/O operations. The single thread refers to the Event Loop thread — the one that runs your JS code.
Node.js runs on the Google V8 JavaScript engine. JavaScript itself was originally designed to run in browsers to handle simple interactions (like button clicks). For these tasks, a single thread was safer because it avoided the complexity of multiple threads trying to change the same piece of UI at the same time. Node.js adopted this same single-threaded model for the Main Thread.
Each thread consumes ~2MB of memory, 10,000 concurrent users = ~20GB RAM just for threads
Context switching between threads is expensive
Race conditions, deadlocks, mutex locks — complex bugs
Most thread time is spent waiting (I/O), not computing
Most thread time is spent waiting (I/O), not computing.
Single thread saves memory.
Avoid bugs arising from handling multiple threads and race consitions, deadlocks etc.
I/O is delegated to libuv which may use multiple threads.
Node.js is single-threaded to minimize complexity and maximize scalability for I/O-bound applications (like APIs, chat apps, and streaming). It relies on the 'Event Loop' to delegate heavy lifting elsewhere so the main thread stays free to receive new orders.
While the Main Thread (where your JavaScript code runs) is single-threaded, Node.js actually uses a library called Libuv under the hood. Libuv maintains a Thread Pool (usually 4 threads by default). When you perform 'heavy' tasks that the system kernel can't handle asynchronously—like encrypting a password (crypto) or compressing a file (zlib)—Node.js offloads those to this hidden pool of threads.