MediumWhy Node.js Can Handle Thousands of Connections While Traditional Threads Struggle | by vnrajasekhar | Medium
Sitemap
vnrajasekhar

vnrajasekhar

Why Node.js Can Handle Thousands of Connections While Traditional Threads Struggle

5 min readJul 12, 2026

--

A practical journey through Worker Threads, Thread Pools, and Event Loops

Every developer eventually encounters this question:

If Node.js runs JavaScript on a single thread, how can it handle thousands of users at the same time?

At first glance, it sounds impossible. We’ve been taught that more work requires more threads, and more threads require more CPU cores. Yet Node.js powers chat applications, APIs, streaming platforms, and real-time systems that serve massive numbers of concurrent connections.

The answer lies in understanding how modern systems manage waiting.

To truly understand this, we need to explore three execution models:

  • Worker Threads — the traditional “one thread does one job” approach.
  • Thread Pools — a controlled and optimized version of multi-threading.
  • Event Loops — the asynchronous model used by Node.js and many modern runtimes.

Concurrency vs. Parallelism: The Foundation

Before diving into threads and event loops, it’s important to distinguish two terms that are often used interchangeably.

Concurrency

Concurrency means dealing with multiple tasks at once.

A single execution thread can switch between tasks, making progress on each of them over time.

Parallelism

Parallelism means performing multiple tasks at the exact same moment.

This requires multiple CPU cores so that different instructions can execute simultaneously.

Think of a restaurant:

  • Concurrency: One chef manages several orders by switching between them.
  • Parallelism: Several chefs cook different orders at the same time.

Most web applications need high concurrency far more than they need raw parallelism.

The Traditional Model: Worker Threads

In a traditional multi-threaded server, every incoming request is handled by a separate operating system thread.

The workflow is straightforward:

  • A request arrives.
  • The OS creates or assigns a worker thread.
  • The thread processes the request.
  • The thread finishes and returns to the pool or terminates.

Why this is powerful

Worker threads excel at CPU-intensive tasks such as:

  • Machine learning inference
  • Video encoding
  • Image processing
  • Heavy mathematical computations

On an 8-core machine, multiple worker threads can truly run in parallel.

The hidden cost

Threads are not free.

Each thread consumes memory, often around 1 MB or more just to exist. If a server creates thousands of threads, memory usage explodes and the operating system spends increasing time performing context switching — saving and restoring thread state instead of executing useful code.

In other words, too many threads can make the server slower, not faster.

Thread Pools: A Smarter Version of Multi-Threading

Press enter or click to view image in full size

To avoid creating unlimited threads, many enterprise servers use a thread pool.

Instead of spawning new threads continuously, the application creates a fixed number of worker threads at startup.

How a thread pool works

  • Incoming tasks are placed in a queue.
  • Available threads pull tasks from the queue.
  • When a thread finishes, it grabs the next task.
  • If all threads are busy, new tasks must wait.
Press enter or click to view image in full size

Benefits

  • Predictable memory usage
  • Better stability under heavy load
  • Reduced thread creation overhead

The starvation problem

Imagine a pool of 100 threads.

If all 100 threads are waiting for slow database responses, the 101st request cannot start, even if the CPU is almost idle.

This is called thread pool starvation.

The system appears overloaded because every worker is blocked waiting for external resources.

The Event Loop: Node.js’s Secret Weapon

Press enter or click to view image in full size

Node.js takes a radically different approach.

Get vnrajasekhar’s stories in your inbox

Join Medium for free to get updates from this writer.

Instead of assigning a thread per request, it uses one main JavaScript thread that continuously processes events.

What happens during an I/O operation?

  • A request arrives.
  • Node.js starts a database query or network request.
  • The actual waiting is delegated to the operating system or libuv.
  • The main thread immediately returns to handling other requests.
  • When the I/O completes, a callback is placed into a queue.
  • The event loop executes the callback when it becomes free.

A real-world analogy

Imagine a short-order cook.

The cook puts a burger on the grill. Instead of standing there watching it cook, they start preparing fries, take another order, and serve drinks.

When the burger is ready, they come back to finish it.

That’s exactly how the event loop handles asynchronous work.

Why Node.js Handles 10,000 Connections

Most web servers spend the majority of their time waiting:

  • Waiting for a database query
  • Waiting for an external API
  • Waiting for a file read
  • Waiting for a network response

Traditional threads remain occupied during that waiting period.

The Node.js event loop does not.

Because waiting is offloaded to the OS/runtime, a single thread can manage thousands of concurrent connections with minimal memory overhead.

What Happens During a Slow Database Query?

Traditional Threaded Server (Blocking)

Five simultaneous users → five blocked threads for three seconds.

If the thread limit is reached, additional users must wait in a queue.

Node.js Event Loop (Non-blocking)

Five simultaneous users → the same single thread registers all requests and continues processing other traffic while the database work happens in the background.

The Catch: Event Loops Hate CPU Work

The event loop is excellent for I/O-heavy applications, but it has one major weakness.

CPU-bound work blocks everything (Single-threaded bottleneck)

If the main JavaScript thread enters a heavy computation, the entire server stops responding until the computation finishes.

This is why Node.js introduced worker_threads for CPU-intensive tasks.

The Architecture of Modern Node.js

Many developers say “Node.js is single-threaded,” but that statement is only partially true.

The JavaScript execution model is single-threaded, but under the hood Node.js uses:

  • The Event Loop for handling requests and callbacks.
  • A libuv Thread Pool for file system operations, DNS lookups, and other blocking tasks.
  • Optional Worker Threads for heavy CPU computations.

In practice, Node.js is a hybrid architecture that combines asynchronous I/O with multi-threading.

When Should You Use Each Model?

Workload — Best Choice

  • REST APIs → Event Loop
  • Chat applications → Event Loop
  • WebSocket servers → Event Loop
  • Image processing → Worker Threads
  • Video encoding → Worker Threads
  • Machine learning inference → Worker Threads
  • General enterprise backends → Thread Pools

The Big Takeaway

The biggest misconception is that more threads automatically mean better performance.

For CPU-bound work, multiple threads are often the right answer.

For I/O-bound web applications, the bottleneck is usually waiting on external systems, not executing CPU instructions. In that environment, an Event Loop can dramatically outperform a thread-per-request architecture because it refuses to waste threads on waiting.

That’s why modern systems increasingly combine both approaches:

  • Java and C# rely heavily on thread pools.
  • Node.js uses an event loop with a background thread pool.
  • Python asyncio follows the same event-driven philosophy.
  • High-performance platforms often mix asynchronous I/O with dedicated worker threads.

The question to ask is not:

“Which model is best?”

The real question is:

“Is my application waiting on I/O, or burning CPU?”

Once you answer that, choosing between Worker Threads, Thread Pools, and an Event Loop becomes much easier — and you’ll understand exactly why Node.js can handle thousands of connections while traditional thread-based systems often struggle.

--

--