Understanding the Node.js Event Loop (For Real This Time)
August 16, 2025
Most explanations of the Node.js event loop stay abstract. Here's a version grounded in an actual code example, because the phase ordering only really sinks in once you can predict the output.
The Phases, In Order
- Timers — runs callbacks scheduled by
setTimeout/setInterval - Pending callbacks — certain system-level callbacks
- Poll — retrieves new I/O events, executes I/O callbacks
- Check — runs
setImmediatecallbacks - Close callbacks — e.g.
socket.on('close')
Microtasks Jump the Queue
Promises (.then) and process.nextTick aren't part of the phase cycle above — they run in a microtask queue that's fully drained after every single callback, before the event loop moves to the next phase.
A Concrete Example
console.log('start');
setTimeout(() => console.log('timeout'), 0);
setImmediate(() => console.log('immediate'));
Promise.resolve().then(() => console.log('promise'));
process.nextTick(() => console.log('nextTick'));
console.log('end');
// Output:
// start
// end
// nextTick
// promise
// timeout (or immediate — order can vary here)
// immediate (or timeout)
Why This Matters in Practice
A synchronous CPU-heavy loop blocks the entire event loop — no timers, no I/O callbacks, nothing runs until it finishes, even in a language people call "non-blocking." Understanding the phases is really about understanding what Node.js is doing while your code is idle, which is most of the time in a typical I/O-bound server.