What is the difference between process.nextTick() and setImmediate()?
process.nextTick() vs setImmediate()
Both are used to schedule asynchronous callbacks in Node.js, but they operate in different phases of the event loop and have different priorities.
process.nextTick()
Fires immediately after the current operation completes, before the event loop continues to the next phase. It has the highest priority among all async scheduling mechanisms.
console.log('1 - start');
process.nextTick(() => {
console.log('2 - nextTick');
});
console.log('3 - end');
// Output:
// 1 - start
// 3 - end
// 2 - nextTickKey characteristics:
- Executes before any I/O events or timers
- Runs in the microtask queue (same as resolved Promises)
- Recursive
nextTickcan starve I/O — be careful!
// ⚠️ This will starve I/O — the callback runs forever
function recursiveNextTick() {
process.nextTick(recursiveNextTick);
}
recursiveNextTick();
// setTimeout, setImmediate, I/O will NEVER firesetImmediate()
Fires on the next iteration of the event loop, specifically in the check phase — after the I/O poll phase completes.
console.log('1 - start');
setImmediate(() => {
console.log('2 - setImmediate');
});
console.log('3 - end');
// Output:
// 1 - start
// 3 - end
// 2 - setImmediateKey characteristics:
- Runs in the check phase of the event loop
- Does not starve I/O — always yields to pending I/O first
- Preferred for deferring work to the next iteration
Side-by-side comparison
setImmediate(() => console.log('setImmediate'));
process.nextTick(() => console.log('nextTick'));
Promise.resolve().then(() => console.log('Promise'));
// Output (always):
// nextTick
// Promise
// setImmediateEvent Loop Priority Order
| Priority | Mechanism | Queue |
|---|---|---|
| 1 (highest) | process.nextTick() | Microtask |
| 2 | Promise.then() | Microtask |
| 3 | setTimeout(fn, 0) | Timers phase |
| 4 | setImmediate() | Check phase |
Inside an I/O callback
When called inside an I/O callback, setImmediate always fires before setTimeout:
const fs = require('fs');
fs.readFile(__filename, () => {
setTimeout(() => console.log('setTimeout'), 0);
setImmediate(() => console.log('setImmediate'));
});
// Output (always):
// setImmediate
// setTimeoutWhen to use which?
| Use case | Recommendation |
|---|---|
| Must run before any I/O | process.nextTick() |
| Defer to next event loop iteration | setImmediate() |
| After I/O completion | setImmediate() |
| Emit events after constructor | process.nextTick() |
const EventEmitter = require('events');
class MyEmitter extends EventEmitter {
constructor() {
super();
// Emit after constructor returns so listeners can attach
process.nextTick(() => {
this.emit('ready');
});
}
}
const emitter = new MyEmitter();
emitter.on('ready', () => console.log('ready!'));
// Works! 'ready!' is printedBest practice: Use
setImmediate()by default. Reserveprocess.nextTick()for cases where you specifically need to run code before any I/O, and avoid recursivenextTickcalls to prevent I/O starvation.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.