Back to JavaScript
JavaScript
easy
mid

What is Node.js and how does its event loop differ from the browser's?

Node.js is a JS runtime built on V8 that runs JS outside the browser, using libuv for async I/O. Its event loop has distinct phases — timers, pending callbacks, poll, check (setImmediate), close — and between every phase it drains microtasks (Promises) and process.nextTick (which runs even before Promises). Same single-threaded model, different phase structure than the browser.

6 min read·~10 min to think through

Node.js is a JavaScript runtime that runs JS outside the browser — on the server, in CLIs, in tooling. It's built on V8 (the same engine as Chrome) plus libuv, a C library that provides the event loop and async I/O.

What Node adds over the browser

  • No DOM / window; instead: fs, http, net, process, Buffer, streams.
  • libuv thread pool for file I/O, DNS, crypto, compression (so blocking syscalls don't block the JS thread).
  • CommonJS require (and now ESM).

It's still single-threaded for your JS — concurrency comes from libuv + the event loop, same philosophy as the browser.

Node's event loop: phases

The browser has "macrotask queue + microtask queue." Node's loop is more structured — it runs through phases in order, each with its own callback queue:

ts
   ┌───────────────────────────┐
┌─▶│   timers   (setTimeout/Interval callbacks due)
│  ├───────────────────────────┤
│  │ pending callbacks (some system I/O callbacks)
│  ├───────────────────────────┤
│  │ poll       (retrieve I/O events; execute I/O callbacks)
│  ├───────────────────────────┤
│  │ check      (setImmediate callbacks)
│  ├───────────────────────────┤
└──│ close callbacks (e.g. socket 'close')
   └───────────────────────────┘

The two microtask-like queues

Between every phase (and between each callback), Node drains two queues, in this priority:

  1. process.nextTick queue — runs first, even before Promises. Highest priority.
  2. Promise microtask queue.then/await continuations.
js
setTimeout(() => console.log("timeout"));
setImmediate(() => console.log("immediate"));
Promise.resolve().then(() => console.log("promise"));
process.nextTick(() => console.log("nextTick"));
console.log("sync");
// sync, nextTick, promise, timeout, immediate
// (sync first; then nextTick > promise; then timers phase, then check phase)

setImmediate vs setTimeout(fn, 0)

  • setImmediatecheck phase, runs after I/O/poll.
  • setTimeout(fn, 0)timers phase.
  • Inside an I/O callback, setImmediate reliably runs before setTimeout(0); at the top level the order isn't guaranteed.

Browser vs Node — the summary

BrowserNode
EngineV8 (Chrome) / othersV8
Async backboneWeb APIslibuv
Loop structuretask + microtask queuesphased loop + microtasks per phase
Extra priority queueprocess.nextTick (before Promises)
setImmediatenot standardcheck phase

Senior framing

The senior points: (1) Node is V8 + libuv, single-threaded JS with a thread pool for I/O; (2) its loop is phased, not a flat task queue; (3) process.nextTick outranks even Promises and can starve the loop if abused; (4) setImmediate vs setTimeout(0) ordering is deterministic inside I/O callbacks. That phase model is what distinguishes Node knowledge from generic event-loop knowledge.

Follow-up questions

  • What's the difference between process.nextTick and setImmediate?
  • How can process.nextTick starve the event loop?
  • What does libuv's thread pool handle?
  • How does Node's loop differ from the browser's?

Common mistakes

  • Assuming Node's event loop is identical to the browser's.
  • Thinking Node is multi-threaded for JS execution.
  • Overusing process.nextTick and starving I/O.
  • Assuming setImmediate always beats setTimeout(0).

Edge cases

  • setImmediate vs setTimeout(0) order is only guaranteed inside an I/O callback.
  • A long synchronous task or recursive nextTick blocks the whole server.
  • Worker threads exist for true CPU parallelism, separate from the loop.

Real-world examples

  • Express/Fastify servers, build tools, CLIs, streaming file processing.

Related questions