process.nextTick
process.nextTick schedules a callback to run after the current operation completes but before the event loop continues to the next phase. It is not technically part of the event loop—it runs between phases.
nextTick is the 'one more thing' friend who keeps saying 'wait, one more thing!' before you can leave the room. Recursive nextTick = that friend who never lets you leave. Ever. I/O starves to death at the door.
nextTick callbacks are stored in a separate nextTick queue that is drained completely before the event loop advances. This makes nextTick useful for deferring work until the current synchronous call stack unwinds, ensuring that event emitters fire after constructors finish setting up listeners. It has higher priority than setImmediate and Promise microtasks.
Because the nextTick queue is drained completely before any I/O callbacks or timers, a recursive nextTick (a callback that schedules another nextTick) creates an infinite synchronous loop that permanently blocks the event loop—all pending I/O, timers, and HTTP requests queue up indefinitely. Node.js does not impose a recursion limit on nextTick. In older Node.js code, nextTick was used to make APIs consistently async (to prevent Zalgo—the half-sync, half-async problem). Today, Promise.resolve().then() is often preferred because it doesn't starve I/O as aggressively.
process.nextTick fires after the current synchronous code but before any I/O callbacks, timers, or setImmediate callbacks. It drains its entire queue before the event loop progresses. The risk: recursive nextTick calls starve I/O indefinitely. Use it for deferring work that must happen before I/O but after the current call stack, such as emitting events post-construction.
Using process.nextTick for recursion (e.g., recursive async iteration) instead of setImmediate starves the event loop. setImmediate yields to I/O between each callback; nextTick does not. This is a classic production footgun disguised as a micro-optimization.