← Node & Express

Node Fundamentals

What is Node.js and how does it manage to serve many requests at the same time with a single thread?

Show answer — try answering out loud first

Node.js is a JavaScript runtime that runs outside the browser, built on top of Chrome's V8 engine. It uses a single-thread model with an event loop, and works in an event-driven and non-blocking way. Thanks to this it can handle thousands of simultaneous connections without creating a thread for each one.

Before, JavaScript only lived inside the browser. Node.js took the V8 engine (the one that runs JavaScript in Google Chrome) and packaged it so you could run JavaScript directly on your computer or server. This way you can write an application's backend (APIs, web servers) using the same language as on the frontend.

Node rests on three key ideas:

  • Single thread: your JavaScript code runs on a single main thread. There aren't 100 threads serving 100 users; there is just one coordinating everything.
  • Event loop: it's a cycle that is always watching for "is there anything to do?". When a task finishes (for example, a file finished being read), the event loop takes the result and runs the function that was supposed to run afterward.
  • Non-blocking: when Node needs something slow (reading a file, querying a database, waiting for the network), it does not sit around waiting. It delegates that task to the system (through the libuv library), keeps serving other requests, and when the slow task finishes, it is notified with an event.

Why can a single thread serve many users? Because most of a server's work is not computation, it's waiting: waiting for the database, waiting for the network, waiting for the disk. Node does not waste the thread waiting; it uses it to serve others while the slow operations happen "on the outside". It's like a waiter who takes your order, sends it to the kitchen, and instead of standing idle in front of the kitchen, serves other tables until your dish is ready.

Its ideal use cases are:

  • REST APIs and web services (many short requests).
  • Real-time applications (chats, notifications, games) with WebSockets.
  • Microservices and gateways.
  • Command-line tools.

It is not the best choice for CPU-intensive work (processing video, heavy mathematical calculations), because that does block the single thread.

// A minimal HTTP server, without external libraries.
const http = require("http");

// createServer receives a function that runs on EVERY request.
const server = http.createServer((req, res) => {
  res.writeHead(200, { "Content-Type": "text/plain" });
  res.end("Hola desde Node.js\n");
});

// The server "listens" on port 3000.
server.listen(3000, () => {
  console.log("Servidor corriendo en http://localhost:3000");
});

// Node does NOT end here: the event loop stays alive waiting for requests.
// A single thread serves all users that arrive.

Thinking that "single-thread" means Node can only do one thing at a time and that's why it's slow. In reality, the single thread only runs your JavaScript code; the input/output (I/O) operations are handled by libuv in the background, using a pool of operating system threads. That's why Node is extremely fast with I/O tasks, even though your JavaScript runs on a single thread. What does slow it down is putting heavy CPU calculations on that thread, because there you really do block everything.

"Node.js is a runtime that lets you run JavaScript outside the browser, built on top of Chrome's V8 engine. Its model is single-threaded with an event loop, event-driven and non-blocking. The key is that Node does not sit waiting on slow operations like reading disk or querying a database: it delegates those tasks to libuv and keeps serving other requests, and when the operation finishes it runs the corresponding callback. That's why it can serve thousands of connections with a single thread, because most of a server's time goes into waiting on I/O, not computing. I use it for APIs, microservices and real-time applications; what I would avoid is putting heavy CPU tasks on the main thread."

Quick challenge

If a single thread serves all requests, what happens if inside a request handler I put a while that takes 10 seconds computing something?

See answer

You block the event loop completely. During those 10 seconds, Node cannot serve any other request: all other users are left waiting, because the single thread is busy with your while. This is the danger of heavy CPU work in Node. The solutions are to move that computation off the main thread using Worker Threads, a child process (child_process), or a job queue in a separate service.