What is the difference between process.nextTick, setImmediate and setTimeout in Node.js?
process.nextTick runs right after the current operation, before promise callbacks and before the event loop moves on. setImmediate runs in the check phase, right after I/O polling. setTimeout(fn, 0) runs in the timers phase after at least about 1 ms.
Explain it simply
Picture an IRCTC ticket counter. The clerk is helping one person. process.nextTick is like saying "one more small thing before you call the next person" to the clerk. It jumps ahead of everyone. setImmediate is like taking a token for the very next round of the queue. setTimeout(fn, 0) is like asking to be called back "after at least a moment", which goes through the timer check at the start of a round.
All three schedule a function to run later, but they land in different places, so they run in a different order.
Example
setTimeout(() => console.log("timeout"), 0);
setImmediate(() => console.log("immediate"));
Promise.resolve().then(() => console.log("promise"));
process.nextTick(() => console.log("nextTick"));
console.log("sync");
// sync
// nextTick
// promise
// then "timeout" and "immediate", in either orderThe first three lines are always the same: synchronous code, then the nextTick queue, then promise microtasks. When this runs in the main script, the order of timeout and immediate is not guaranteed. It depends on whether 1 ms has already passed when the event loop starts.
How it works
Node's event loop goes through phases in a cycle:
- timers: runs expired
setTimeoutandsetIntervalcallbacks. - pending callbacks: some deferred system callbacks.
- poll: waits for and runs I/O callbacks (file reads, sockets).
- check: runs
setImmediatecallbacks. - close callbacks: such as
socket.on("close").
Between each callback, Node empties two queues: first the process.nextTick queue, then the promise microtask queue. That is why nextTick beats a resolved promise.
Real-world use
setImmediateis useful to break a long job into chunks so that I/O can be handled between chunks.process.nextTickis used inside libraries to make a callback always asynchronous, for example emitting an error event after the caller has had a chance to attach a listener.setTimeoutis for real delays, like retrying a failed payment status check after 2 seconds.
Common mistakes
- Assuming
setTimeout(fn, 0)always runs beforesetImmediate. Outside an I/O callback, the order can change from run to run. - Calling
process.nextTickrecursively. The loop never reaches the poll phase, so I/O starves. - Thinking "immediate" means "right now". The name is historical;
nextTickactually runs sooner.
What to say in the interview
"All three defer work, but at different points. process.nextTick callbacks run as soon as the current operation finishes, even before promise callbacks. setImmediate runs in the check phase, right after the poll phase handles I/O. setTimeout with zero delay runs in the timers phase once at least a millisecond has passed. Inside an I/O callback, setImmediate always runs before a zero timeout. In the main module that order is not guaranteed. I prefer setImmediate or queueMicrotask over nextTick unless I really need to run before everything else."
Follow-up questions
- Why can recursive
process.nextTickfreeze a server? - Inside an
fs.readFilecallback, which runs first:setTimeout(fn, 0)orsetImmediate? - Where do
awaitcontinuations run in Node?
Go deeper
Read these once the basics above feel easy.
Inside an I/O callback the loop is in the poll phase, and the check phase comes next, so setImmediate is guaranteed to run before a zero-delay timer, which has to wait for the next timers phase. Also note that Node clamps a delay of 0 to 1 ms. The Node docs recommend setImmediate for most cases because it is easier to reason about, and process.nextTick is described as running before any other I/O or timer work in the current iteration.