Skip to main content

Command Palette

Search for a command to run...

How Node.js Handles Multiple Requests with a Single Thread

Published
5 min read
D
Turning confusing web concepts into simple, real-world explanations. Writing about JavaScript, Node.js, and how things actually work.

One of the most confusing things about Node.js is this:

“Node.js is single-threaded.”

And immediately another question appears:

“Then how can it handle thousands of requests at the same time?”

At first, this sounds impossible.

If only one thread exists, shouldn’t requests wait one by one?

The answer lies in:

  • asynchronous programming

  • the event loop

  • background workers

The important idea is:

Node.js handles concurrency, not true parallel execution of JavaScript.

Let’s understand how this actually works.


What Does Single-Threaded Mean?

A thread is a sequence of execution.

Single-threaded means:

  • JavaScript code runs on one main thread

  • one operation executes at a time

Example:

console.log("A");
console.log("B");
console.log("C");

Execution order:

A
B
C

One line runs after another.


Thread vs Process

These terms are often confused.

Process

A running application instance.

Example:

  • Chrome browser process

  • VS Code process

  • Node.js process


Thread

A worker inside a process that executes tasks.

A process may contain:

  • one thread

  • multiple threads

Node.js mainly executes JavaScript on a single main thread.


The Big Problem

Imagine Node.js handled requests synchronously.

Example:

app.get("/", () => {
  readHugeFile();
});

If file reading blocks the thread:

  • request 2 must wait for request 1

  • request 3 waits even longer

  • entire server slows down

This would make Node.js terrible for scalable servers.

But Node.js works differently.


The Chef Analogy

Imagine a chef in a restaurant.

The chef:

  • takes orders

  • starts cooking

  • moves to the next order while food cooks

The chef does not stand still watching food cook.

Node.js behaves similarly.

It:

  • receives requests

  • delegates slow tasks

  • continues handling new requests

This is concurrency.


What Is the Event Loop?

The event loop is the system that keeps Node.js running continuously.

It checks:

  • completed tasks

  • pending callbacks

  • timers

  • incoming requests

Its job is basically:

“Keep processing available work without blocking.”


How Node.js Handles Requests

Imagine 3 users send requests simultaneously.

Example:

Request 1 → database query
Request 2 → file read
Request 3 → API call

Node.js does not process them fully one-by-one.

Instead:

  1. receives request

  2. delegates slow operation

  3. continues handling next request

This allows many requests to stay active together.


Delegating Tasks to Background Workers

Here’s the important part:

Node.js itself does not perform heavy operations directly on the main thread.

Operations like:

  • file system access

  • database queries

  • network requests

  • cryptography

are delegated to:

  • operating system

  • libuv worker pool

  • external systems


Example Flow

Client sends request
↓
Node.js receives request
↓
Slow task delegated
↓
Main thread becomes free again
↓
Node.js handles other requests
↓
Task completes later
↓
Callback added to event loop
↓
Response sent

This is the core reason Node.js scales well.


Example With File Reading

const fs = require("fs");

app.get("/", (req, res) => {
  fs.readFile("large.txt", "utf-8", (err, data) => {
    res.send(data);
  });
});

Important detail:

While the file is being read:

  • Node.js is NOT blocked

  • other requests continue executing

The file reading happens outside the main JavaScript execution flow.


Concurrency vs Parallelism

This distinction is extremely important.


Concurrency

Handling multiple tasks efficiently by switching between them.

Node.js is excellent at this.

Example:

  • start task

  • move to another task

  • return when first task finishes


Parallelism

Actually executing multiple CPU operations simultaneously.

Pure JavaScript execution in Node.js is not parallel by default.

One main thread executes JavaScript.


Why Node.js Performs Well

Node.js is extremely efficient for:

  • APIs

  • chat applications

  • streaming

  • real-time systems

  • I/O-heavy applications

Because most server work involves waiting:

  • waiting for database

  • waiting for network

  • waiting for files

Instead of blocking during waiting, Node.js continues serving other requests.


Important Limitation

Node.js is not magically fast for everything.

CPU-heavy tasks can still block the event loop.

Example:

  • video processing

  • large calculations

  • image manipulation

If one CPU-intensive task runs too long:

  • entire event loop gets delayed

  • all requests slow down

That’s why worker threads or separate services are often used for heavy computation.


What Makes Node.js Scalable

The scalability comes from:

  • non-blocking I/O

  • async execution

  • efficient request handling

  • lightweight concurrency model

Instead of creating:

  • one thread per request

Node.js efficiently manages many connections with very few threads.

This reduces:

  • memory overhead

  • thread switching cost

  • system complexity


Simple Mental Model

Think of Node.js like this:

Main Thread

“Coordinates work.”


Background Workers / OS

“Handle slow operations.”


Event Loop

“Checks completed tasks and continues execution.”


Full Request Lifecycle

Client sends request
↓
Node.js receives it
↓
Slow operation delegated
↓
Event loop continues processing
↓
Other requests handled meanwhile
↓
Operation completes
↓
Callback queued
↓
Response returned

Node.js handles multiple requests efficiently not because JavaScript runs in parallel, but because it avoids blocking operations.

The key idea is:

  • JavaScript runs on a single main thread

  • slow tasks are delegated elsewhere

  • the event loop keeps processing available work

This allows Node.js to handle massive numbers of concurrent connections efficiently with a relatively lightweight architecture.

Once you understand:

  • event loop

  • non-blocking I/O

  • delegation of slow tasks

the “single-threaded but scalable” nature of Node.js starts making complete sense.