The 6 Phases of the Event Loop — Why Your Mental Model of Node.js Is Probably Wrong

The 6 Phases of the Event Loop — Why Your Mental Model of Node.js Is Probably Wrong

Most engineers can recite the phases of the Node.js event loop.

Very few can explain what actually happens in each phase — or why it matters.

That gap leads to subtle production bugs:

  • Timers firing late
  • Unexpected execution order
  • Throughput bottlenecks under load

This article breaks down the real behavior of the event loop — not the simplified version.


The Problem

Most explanations of the Node.js event loop look like this:

“There are phases: timers → pending callbacks → poll → check → close callbacks.”

Technically correct.

Practically misleading.

Because:

  • Engineers assume phases execute uniformly
  • They assume timers are precise
  • They assume async callbacks run “when ready”

None of these are true.

The event loop is not a timeline — it’s a scheduling system influenced by I/O, queues, and system state.


Why It Happens

At its core, Node.js uses libuv’s event loop, which:

  • Maintains multiple internal queues
  • Runs them in a fixed phase order
  • Delegates I/O to the OS or threadpool
  • Executes callbacks only when results are ready

But here’s the key insight:

The poll phase controls everything.

Why?

Because:

  • It waits for I/O
  • It decides whether to block or continue
  • It determines when timers/check phases execute

This means the event loop is not strictly cyclical — it’s adaptive.


Internal Architecture

Let’s look at the actual phases:

  1. Timers Phase

    • Executes callbacks from setTimeout and setInterval
    • Only if their threshold has passed
  2. Pending Callbacks

    • Executes deferred system-level callbacks (e.g., TCP errors)
  3. Idle / Prepare

    • Internal use (libuv housekeeping)
  4. Poll Phase

    • Fetches new I/O events
    • Executes I/O callbacks
    • Can block if nothing else is scheduled
  5. Check Phase

    • Executes setImmediate callbacks
  6. Close Callbacks

    • Executes cleanup callbacks (e.g., socket close)

Example Scenario

Let’s analyze a classic confusion:

setTimeout(() => console.log("timeout"), 0);

setImmediate(() => console.log("immediate"));

What runs first?

Answer: It depends.

  • If executed in the main script → non-deterministic
  • If inside an I/O callback → setImmediate wins

Why?

Because:

  • After I/O, the loop goes to check phase
  • setImmediate is processed before returning to timers

Diagram

Event Loop Phases

flowchart LR
    Timers --> Pending
    Pending --> Idle
    Idle --> Poll
    Poll --> Check
    Check --> Close
    Close --> Timers

What Actually Happens Per Tick

sequenceDiagram
    participant Loop
    participant Timers
    participant Poll
    participant Check

    Loop->>Timers: Run expired timers
    Loop->>Poll: Process I/O / wait
    Poll-->>Loop: Callbacks ready
    Loop->>Check: Run setImmediate
    Loop->>Timers: Next iteration

Key Takeaways

  • Timers are NOT precise

    • setTimeout(fn, 0) does not mean immediate
    • It means “execute after minimum threshold + loop delay”
  • Poll phase dominates execution

    • If poll is busy → timers are delayed
    • If poll is idle → loop may block waiting for I/O
  • setImmediate ≠ setTimeout(fn, 0)

    • Different queues
    • Different phases
    • Different guarantees
  • Event loop is adaptive, not fixed

    • Behavior changes based on:

      • I/O load
      • Queue sizes
      • System timing

Final Thoughts

Senior engineers don’t just memorize event loop phases.

They understand:

  • when phases execute
  • why delays happen
  • how system load reshapes behavior

The biggest mental shift is this:

Node.js is not executing your code in order — it is scheduling callbacks based on system state.

And once you internalize that, debugging async behavior becomes dramatically easier.


Next in the series: Microtasks vs Macrotasks — Why Promises Can Starve Your Event Loop


Next in the Series

Continue reading: setTimeout(0) vs setImmediate(): The Event Loop Trap That Exposes Senior Engineers