Skip to content
OnDevKit
Interview

Node.js event loop interview questions: 8 tested answers

Node.js event loop interview questions with real, tested output: nextTick vs promises, setTimeout vs setImmediate, async/await, and the ES module twist.

Published · 4 min read
On this page

These Node.js event loop interview questions show up again and again: "what does this code print?" Below are 8 output puzzles with the answer and a one-line reason you can say out loud. Every output here was produced by running the code on Node.js 26, several times each, so you're learning what Node actually does, not what a blog assumed.

How does the Node.js event loop work?

The event loop is how Node.js runs async callbacks on one thread. Your synchronous code runs first. Then Node keeps cycling through phases, running whatever callbacks are ready. The main phases, in order, are timers, pending callbacks, poll (I/O), check (setImmediate) and close callbacks (Node.js event loop guide).

Between callbacks, Node empties two small queues:

  • the nextTick queue (process.nextTick callbacks);
  • the microtask queue (promise .then callbacks, await continuations, queueMicrotask).
Order used in Node.js event loop interview questions: synchronous code, then nextTick, then promise microtasks, then timers and setImmediate.

That order explains most answers below. All puzzles are CommonJS files (.js) unless they say otherwise.

Question 1: nextTick, promise and setTimeout

console.log('A');
setTimeout(() => console.log('B'), 0);
Promise.resolve().then(() => console.log('C'));
process.nextTick(() => console.log('D'));
console.log('E');

Output: A E D C B

Why: sync code (A, E) first; then the nextTick queue (D); then promise microtasks (C); then the timers phase (B).

Question 2: setTimeout vs setImmediate

setTimeout(() => console.log('timeout'), 0);
setImmediate(() => console.log('immediate'));

Output: not guaranteed.

Why: the Node.js docs say this order is "non-deterministic, as it is bound by the performance of the process". In our test it printed immediate first in 20 out of 20 runs, but don't rely on that; the docs show both orders as possible. Saying "it depends, and here's why" is the answer interviewers want.

Question 3: the same, inside an I/O callback

const fs = require('node:fs');
fs.readFile(__filename, () => {
  setTimeout(() => console.log('timeout'), 0);
  setImmediate(() => console.log('immediate'));
});

Output: immediate timeout (every time)

Why: the callback runs in the poll phase. The check phase (setImmediate) comes right after poll, before the loop gets back to timers. The docs say the immediate is "always executed first" here.

Question 4: nextTick inside a promise

Promise.resolve().then(() => console.log('promise 1'));
process.nextTick(() => console.log('tick 1'));
Promise.resolve().then(() => {
  console.log('promise 2');
  process.nextTick(() => console.log('tick 2'));
});
process.nextTick(() => console.log('tick 3'));

Output: tick 1, tick 3, promise 1, promise 2, tick 2

Why: both ticks queued during sync code run before any promise. tick 2 is queued while the microtask queue is being drained, so it waits until those promises finish.

Question 5: async/await

async function run() {
  console.log('1');
  await null;
  console.log('2');
}
console.log('3');
run();
console.log('4');

Output: 3 1 4 2

Why: an async function runs synchronously until its first await. Everything after await becomes a microtask, so 2 prints after the remaining sync code (4).

Question 6: a promise inside a timer

setTimeout(() => {
  console.log('timeout 1');
  Promise.resolve().then(() => console.log('promise inside timeout'));
}, 0);
setTimeout(() => console.log('timeout 2'), 0);

Output: timeout 1, promise inside timeout, timeout 2

Why: in current Node.js, microtasks run after each timer callback, not after the whole batch of timers. So the promise slips in between the two timers.

Question 7: var vs let in a loop

for (var i = 0; i < 3; i++) setTimeout(() => console.log('var', i), 0);
for (let j = 0; j < 3; j++) setTimeout(() => console.log('let', j), 0);

Output: var 3, var 3, var 3, let 0, let 1, let 2

Why: var creates one shared i, which is already 3 when the timers run. let creates a new j for each loop pass. This is really a closure question wearing an event loop costume.

Question 8: blocking the event loop

const start = Date.now();
setTimeout(() => console.log('ran after', Date.now() - start >= 500 ? '500+ ms' : 'less than 500 ms'), 100);
while (Date.now() - start < 500) {}
console.log('loop done');

Output: loop done, ran after 500+ ms

Why: the while loop blocks the only thread. The timer is ready at 100 ms, but it can't run until the sync code finishes. setTimeout(fn, 100) means "at least 100 ms", never "exactly".

Summary table of the 8 Node.js event loop interview questions with the printed output for each puzzle.

The ES module twist most answers miss

Run Question 1 as an ES module (save it as q1.mjs) and the order changes:

CommonJS (.js):  A E D C B
ES module (.mjs): A E C D B

Promises now run before process.nextTick. The Node.js docs explain why: ES modules are already being processed as part of the microtask queue, so in ESM queueMicrotask() and promise callbacks run before nextTick ones (Node.js process docs).

Comparison of the same Node.js event loop puzzle in CommonJS and ES modules: nextTick runs first in CommonJS, promises run first in ESM.

Quick answers to common Node.js event loop interview questions

  • What is the event loop? The mechanism that lets single-threaded Node.js run async callbacks, by cycling through phases and running ready callbacks.
  • Microtask vs macrotask? Microtasks (promises, queueMicrotask) run right after the current callback. Macrotasks (timers, I/O, setImmediate) wait for their event loop phase.
  • nextTick vs setImmediate? nextTick runs before the loop continues; setImmediate runs in the check phase of the next loop pass. The names are confusingly backwards.
  • Can you starve the event loop? Yes. Recursive process.nextTick calls or a long sync loop stop the loop from reaching I/O.

Next steps

Run the puzzles yourself: paste each into a .js file and run node file.js. Then try a real async bug: fix EADDRINUSE address already in use, which happens inside server.listen(). Also useful before interviews: how to decode a JWT token safely.