Node.js8 min read

Understanding Node.js Event Loop: A Complete Guide

Deep dive into how the Node.js event loop works, including phases, timers, and microtasks.

Sarah Johnson
December 1, 2025
12.5k486

The Node.js event loop is one of the most important concepts to understand when working with Node.js. It's what allows Node.js to perform non-blocking I/O operations despite JavaScript being single-threaded.

What is the Event Loop?

The event loop is what allows Node.js to perform non-blocking I/O operations by offloading operations to the system kernel whenever possible. Since most modern kernels are multi-threaded, they can handle multiple operations executing in the background.

Event Loop Phases

The event loop has several phases, each with a FIFO queue of callbacks to execute:

1. **Timers Phase**: Executes callbacks scheduled by setTimeout() and setInterval() 2. **Pending Callbacks**: Executes I/O callbacks deferred to the next loop iteration 3. **Idle, Prepare**: Used internally 4. **Poll Phase**: Retrieves new I/O events and executes I/O related callbacks 5. **Check Phase**: setImmediate() callbacks are invoked here 6. **Close Callbacks**: Executes close callbacks like socket.on('close')

How It Works

When Node.js starts, it initializes the event loop and processes the provided input script. The script may make async API calls, schedule timers, or call process.nextTick(), then begins processing the event loop.

#Node.js#Event Loop#Async#Performance

Common Questions & Answers

Q1

What is the difference between process.nextTick() and setImmediate()?

A

process.nextTick() fires immediately on the same phase, before the event loop continues. setImmediate() fires on the following iteration or "tick" of the event loop. Despite the names suggesting otherwise, process.nextTick() executes before setImmediate().

javascript
// process.nextTick() executes first
process.nextTick(() => {
  console.log('nextTick');
});

setImmediate(() => {
  console.log('setImmediate');
});

// Output:
// nextTick
// setImmediate
Q2

How does Node.js handle blocking operations?

A

Node.js offloads blocking operations to the system kernel or uses a thread pool (libuv) for operations that cannot be handled by the kernel. This allows the main event loop to continue processing other events while waiting for the blocking operation to complete.

Q3

What are microtasks in the event loop?

A

Microtasks are tasks that execute after the current operation completes and before the event loop continues. Promises and process.nextTick() create microtasks. All microtasks are processed before moving to the next phase of the event loop.

javascript
console.log('Start');

setTimeout(() => console.log('Timeout'), 0);

Promise.resolve().then(() => console.log('Promise'));

process.nextTick(() => console.log('NextTick'));

console.log('End');

// Output:
// Start
// End
// NextTick
// Promise
// Timeout