Backend & Node.js · APIs, data and failure
How does the Node.js event loop work?
Short answer
The event loop repeatedly runs phases for timers, pending callbacks, polling, check callbacks and close callbacks. Between phases it drains microtasks, so promise and nextTick callbacks run before the loop advances.
Node delegates I/O to the operating system and libuv, then processes completed work on a single JavaScript thread. Each loop iteration moves through phases. Timers run expired setTimeout and setInterval callbacks. The poll phase waits for I/O and runs ready callbacks. The check phase runs setImmediate callbacks. Close callbacks handle teardown events.
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");Microtasks versus phases
- The nextTick queue is drained before the promise microtask queue
- Microtasks run after the current operation and between event loop phases
- setTimeout with zero delay is still a timer callback and runs in a later iteration
- setImmediate runs in the check phase, which is why its order against timers is not guaranteed in the main module
- Long synchronous work blocks every phase and delays all callbacks
This design lets one thread keep many connections in flight, because the expensive waiting happens in the OS or the libuv thread pool. It does not make CPU work concurrent. A tight loop blocks timers, I/O callbacks and new requests until it finishes.
Follow-ups you should expect
Interviewers use these to check whether the first answer was understanding or memorisation.
- 1What is the difference between a microtask and a macrotask?
- 2Why is setTimeout(fn, 0) not immediate?
- 3When does setImmediate run before setTimeout?
- 4What happens when a callback blocks the event loop?
Say it in the interview
The event loop is a sequence of phases that process timers, I/O, immediate callbacks and close events. After each phase Node drains the nextTick and promise queues, so microtasks always run before the loop moves on. I/O waits are offloaded, but JavaScript callbacks still share one thread, so any long synchronous block delays everything. That is the core trade-off of the model.
Use this as a model, not a script. Saying it in your own words is what makes it survive follow-up pressure.
Related questions
Reading is step one
Now say it out loud.
Understanding an answer and delivering it under pressure are different skills. Rehearse this topic in a live Backend & Node.js mock interview and get scored feedback on depth, clarity and confidence.