Back to 20 Concepts
event-loopIntermediate

Microtasks: process.nextTick vs Promise.then

Microtask queues are NOT part of Libuv; they are managed directly by Node.js. process.nextTick has higher priority than Promise microtasks, and both drain completely between every single event loop phase.

Intuitive Mental Model

The VIP Fast-Track Lane: When an airplane lands (an event loop phase finishes), VIP passengers (nextTick) exit first, followed by First Class (Promises), before general passengers (Timers/Poll) can board the next flight.

Node.js ESM / CJS ImplementationNode.js v22 LTS
// 1. Synchronous:
console.log('1. Sync Start');

// Microtask Queue (Promises):
Promise.resolve().then(() => console.log('4. Promise.then (Microtask)'));

// nextTick Queue (Highest Priority Microtask):
process.nextTick(() => console.log('3. process.nextTick (VIP Queue)'));

// Macrotask (Timers Phase):
setTimeout(() => console.log('5. setTimeout (Macrotask)'), 0);

console.log('2. Sync End');
// Output: 1 -> 2 -> 3 -> 4 -> 5

Key Architectural Takeaways

  • Execution Priority: Synchronous Code -> process.nextTick Queue -> Promise Microtask Queue -> Next Libuv Phase.
  • Microtask queues drain completely before the event loop advances to the next phase.
  • A recursive process.nextTick loop will starve the event loop, preventing all I/O, timers, and HTTP requests from ever executing.
Common Production Mistake

Recursively calling process.nextTick(), starving the event loop and freezing I/O completely.

Recommended Solution

Use setImmediate() for recursive task scheduling to allow the Poll phase to process incoming I/O between cycles.