Concurrency

libuv

libuv is a C library that powers Node.js’s async I/O. It handles event loops, asynchronous operations, and thread pools.

Responsibilities of libuv

  • Implements the event loop (so Node.js itself doesn’t need to).

  • Provides a thread pool (default = 4 threads, configurable via UV_THREADPOOL_SIZE).

  • Wraps platform-specific features:

    • Unix: epoll, kqueue, etc.

    • Windows: IOCP (I/O Completion Ports).

  • Handles async operations for:

    • File system (fs module)

    • DNS lookups

    • TCP/UDP sockets

    • Child processes

    • Timers

Single Threaded

Node single threaded execution comes from its roots and engine used.

JavaScript was originally designed for browsers, where single-threaded execution (with an event loop) was the simplest way to manage UI updates and user interactions.

Node.js extends JavaScript to the server but keeps its single-threaded event loop. This design avoids thread-safety issues (like race conditions, deadlocks) since everything executes in a single main thread.

Async IO

Instead of blocking threads for I/O operations (file reads, DB queries, network calls), Node.js uses libuv underneath, which delegates heavy I/O to the OS.

The event loop waits for these operations to finish and then invokes the registered callbacks.

That’s why Node.js can handle tens of thousands of concurrent requests on a single thread.

Absctracted multi threading

Even though your JavaScript code runs in one main thread, Node.js internally can use multiple threads for I/O and background tasks. Example:

  • File system operations (fs module)

  • DNS lookups

  • Crypto operations

These get pushed to libuv’s thread pool (default size = 4, configurable). So Node.js does use threads, but it abstracts them away.

True Parallelism (Multitasking)

If you need CPU-bound parallelism (e.g., image processing, data crunching, encryption), async I/O alone isn’t enough. Node.js provides two main tools:

Worker Threads (since Node.js v10.5.0, stable in v12)

Lets you run multiple threads, each with its own V8 instance.

Perfect for CPU-intensive tasks that would otherwise block the event loop.

circle-info

Here, the worker runs the loop in a separate thread, freeing the main thread.

Cluster Module

Spins up multiple Node.js processes (not threads) that share the same server port.

Useful for scaling across multi-core CPUs.

Load balancing is handled by the master process.

circle-info

Each worker is a separate process (more memory overhead than threads). Best for handling many requests in parallel.

Last updated