process.nextTick(): Cutting in Line on the Event Loop
process.nextTick() schedules a callback to run immediately after the current operation, before the event loop continues to timers or I/O. It's used for API consistency or error handling. The footgun is that overusing it can starve the event loop, blocking I/O.
WHY IT EXISTS: Node.js needs a way to schedule a task to run asynchronously but as soon as possible, before any I/O events. This is crucial for creating consistent APIs where a function might sometimes return a value synchronously and sometimes need to do it asynchronously, preventing what's known as Zalgo.
THE MENTAL MODEL: Think of process.nextTick() as a special "front of the line" pass for the event loop. While setTimeout(fn, 0) puts your task in a queue for a future loop tick, nextTick() runs your task immediately after the current operation finishes, before the event loop even gets to check for timers or I/O events.
HOW IT WORKS: When you call process.nextTick(callback), Node.js adds your callback to the nextTickQueue. After the current JavaScript operation completes and the call stack unwinds, Node.js immediately processes all callbacks in this queue. This queue is processed completely before the event loop proceeds to other phases like the microtask queue (for Promises) or the timers queue, giving it the highest precedence of all async operations.
WHEN TO USE IT: Use nextTick when you need to ensure code runs after the current function's call stack has unwound but before any other async operation. A classic use case is in an event emitter to ensure an event is fired after the object's constructor has finished, making the API predictable. It allows you to give a function an asynchronous API, even if it doesn't do I/O.
WHEN NOT TO USE IT: Do not use nextTick for general-purpose "run later" tasks; setTimeout(fn, 0) or setImmediate(fn) are better for that. The biggest footgun is creating a recursive nextTick loop. Because the nextTickQueue is processed until it's empty before the event loop can continue, a recursive call will starve the event loop, preventing any I/O or timers from running. For most modern use cases, the standard queueMicrotask() is a safer, more portable alternative.
ONE CANONICAL EXAMPLE: An API that might sometimes return a cached value synchronously can use nextTick to always behave asynchronously. For example: if (cached) { process.nextTick(() => callback(cached)); } else { fetchValue(callback); }. This guarantees the callback is never invoked within the same tick as the initial function call, providing a consistent, non-blocking interface.
Read the original → nodejs.org
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.