mediumBackend EngineerTechnology
What is the difference between process.nextTick() and setImmediate() in Node.js, and when would you use each?
Posted 18/04/2026
by Mehedy Hasan Ador
Question Details
Interviewer asked:
"We have code that needs to run 'as soon as possible but not synchronously.' Should we use process.nextTick() or setImmediate()? What's the difference, and what are the production implications?"
Suggested Solution
Execution Order
console.log('1 - sync');
process.nextTick(() => console.log('2 - nextTick'));
Promise.resolve().then(() => console.log('3 - promise microtask'));
setImmediate(() => console.log('4 - immediate'));
setTimeout(() => console.log('5 - timeout'), 0);
// Output: 1, 2, 3, 4/5 (4 and 5 order varies on first event loop cycle)
// On subsequent cycles: always 4 before 5
Where They Run in the Event Loop
┌───────────────────────────────────┐
│ Event Loop Phases (in order): │
│ │
│ 1. Timers (setTimeout/setInterval) │
│ 2. Pending callbacks │
│ 3. Idle, prepare │
│ 4. Poll (I/O) │
│ 5. Check (setImmediate) ◄── HERE │
│ 6. Close callbacks │
│ │
│ BEFORE each phase: │
│ → process.nextTick queue ◄── HERE│
│ → Microtask queue (Promises) │
└───────────────────────────────────┘
Key Differences
| Aspect | process.nextTick() | setImmediate() |
|---|---|---|
| When | Before next event loop phase | After I/O polling (check phase) |
| Priority | Higher than Promises | Lower than nextTick |
| Starvation | Can starve I/O | Cannot starve I/O |
| Queue | nextTickQueue | checkQueue |
The Starvation Problem
// ❌ This will STARVE the event loop — I/O never gets processed
function recursiveNextTick() {
process.nextTick(recursiveNextTick);
}
recursiveNextTick();
// Other callbacks NEVER run!
// ✅ setImmediate allows I/O to process between iterations
function recursiveImmediate() {
setImmediate(recursiveImmediate);
}
recursiveImmediate();
// Other callbacks CAN run between iterations
When to Use Each
process.nextTick()
- Ensuring a callback runs after the current operation but before anything else
- Error handling: ensure errors bubble up before I/O
-
function EventEmitter() { // Allow user to add listener before event fires process.nextTick(() => this.emit('ready')); }
setImmediate()
- Breaking up long CPU operations
- Ensuring I/O gets processed between iterations
-
async function batchProcess(items) { for (let i = 0; i < items.length; i++) { processItem(items[i]); if (i % 100 === 0) { await new Promise(r => setImmediate(r)); // Yield to I/O } } }
Rule: Prefer setImmediate() in production unless you specifically need pre-phase execution.