Skip to main content

Command Palette

Search for a command to run...

The Node.js Event Loop Explained

Updated
3 min readView as Markdown

What the Event Loop Is

The event loop is the system in Node.js that manages and executes tasks.

Simple way to think about it:
The event loop keeps checking for tasks and executes them one by one.

It works together with:

  • the call stack

  • callback queues

  • async operations


Why Node.js Needs an Event Loop

JavaScript is single-threaded, meaning:
It can execute one main task at a time.

Originally, JavaScript only ran inside browsers. Node.js took JavaScript outside the browser and made it possible to run on servers.

To do this:

  • Google Chrome’s V8 engine was used

  • libuv was added

libuv provides:

  • the event loop

  • thread pool

  • async handling for timers, file system, networking, etc.

So Node.js can handle asynchronous operations without blocking the main thread.


Task Queue vs Call Stack (Conceptual)

Call Stack

The call stack is where functions are executed.

function one() {
  two();
}

function two() {
  console.log("runs");
}

one();

Functions are pushed into the stack and removed after execution.


Task Queue

Async callbacks are placed into a queue.

Example:

setTimeout(() => {
  console.log("timer done");
}, 1000);

The callback does not directly go to the stack.

Instead:

  1. Timer runs in background

  2. Callback enters queue

  3. Event loop pushes it to stack when stack becomes empty


How Async Operations Are Handled

Synchronous code always gets higher priority first. The call stack must become empty before async callbacks can execute.

Async operations are handled outside the main thread using libuv.

Examples:

  • timers

  • file system

  • API/network requests

console.log("one");

setTimeout(() => {
  console.log("two");
}, 1000);

console.log("three");

Output:

one
three
two

Why?

  • setTimeout is handled separately

  • Main thread continues execution

  • Callback runs later through event loop


Timers vs I/O Callbacks (High Level)

Synchronous tasks are always completed first before moving to async callbacks.

Node.js event loop works in phases.

Important high-level phases:

  1. Timers phase

    • setTimeout

    • setInterval

  2. I/O callbacks

    • file reading

    • network operations

  3. Immediate callbacks

    • setImmediate
  4. Close callbacks

    • socket close events

Simplified execution order

timers
→ I/O callbacks
→ immediates
→ close callbacks

The event loop continuously checks these phases and executes pending callbacks.


Role of Event Loop in Scalability

The event loop is one of the main reasons Node.js is scalable.

Instead of blocking execution:

  • Node.js delegates async tasks to the system/libuv

  • Main thread stays free

  • More requests can be handled efficiently

This allows Node.js to:

  • handle many connections

  • process multiple async tasks

  • remain fast with fewer resources


Important Clarification

Async code is still asynchronous.

async/await and .then() do not make code synchronous internally.

They only:

make asynchronous code look and behave more like synchronous code.

Under the hood:

  • event loop

  • promises

  • queues

    still handle everything asynchronously.