Node.js and the Event Loop: I/O, and the VIP Microtask You Never Knew Existed
In Post 1 and Post 2, we built a solid mental model of the JavaScript event loop — the call stack, the two queues, Promises, and async/await. Everything we covered lives in the browser.
But JavaScript doesn't only run in browsers. And when it runs elsewhere, the event loop gets a few new additions that change the picture slightly.
This post is about Node.js — what it is, and a special kind of microtask called process.nextTick() that sits above even Promises in the priority queue.
📝 Note: This post was written with the assistance of AI. The content reflects my personal learning and understanding and should not be taken as professional advice. Please do your own research and due diligence before acting on anything written here.
🏥 What Is Node.js?
JavaScript was originally built to run inside browsers — Chrome, Firefox, Safari. It was designed to make webpages interactive. That was its only job.
Node.js changed that. It's a way to run JavaScript outside the browser — on a server, on your laptop, anywhere. Same language, different environment.
Think of it like English spoken in two different professional settings. A doctor in a hospital and a lawyer in a courtroom both speak English — but the words they use, the rules they follow, and the tools they work with are slightly different.
JavaScript in the browser and JavaScript in Node.js are the same language. But Node.js has its own tools and its own additions to the event loop that the browser doesn't have.
The core event loop rules we covered in Post 1 still apply — synchronous first, then microtasks, then macrotasks. Node.js doesn't break those rules. It just adds two new players to the game:
| New Player | What It Is | Covered In |
|---|---|---|
process.nextTick() | A VIP microtask — runs before even Promises | This post |
setImmediate() | A macrotask designed to run right after I/O | Post 4 |
We'll go deep on process.nextTick() in this post. setImmediate() gets its own dedicated post next — because it has some subtle behaviour that deserves full attention.
🎖️ process.nextTick() — The VIP Microtask
Now for the most interesting addition Node.js brings to the event loop — process.nextTick().
In Post 1, we established that microtasks always run before macrotasks. But in Node.js, not all microtasks are equal either. process.nextTick() sits at the very top of the microtask queue — above even Promises.
Think of it like a hospital's priority system. Promises are already in the priority inbox — they get seen before any macrotask. But process.nextTick() is the emergency case that gets rushed in ahead of everyone else in the priority inbox too.
Is process.nextTick() actually a microtask? Technically — it's complicated.
process.nextTick()doesn't sit in the same microtask queue as Promises. Node.js maintains a separatenextTickqueue that gets processed before the regular microtask queue. So while it behaves like a microtask — running before any macrotask — it lives in its own dedicated queue that sits above Promises. Some people argue it isn't a "true" microtask for this reason. The safest way to think about it:process.nextTick()is a VIP microtask — same spirit as a microtask, higher priority, separate queue. This distinction comes up in senior level interviews.
console.log("A"); // synchronous
process.nextTick(() => {
console.log("B"); // VIP microtask — above Promises
});
Promise.resolve().then(() => {
console.log("C"); // regular microtask
});
setTimeout(() => {
console.log("D"); // macrotask
}, 0);
console.log("E"); // synchronous
Output:
A
E
B
C
D
Step by step:
"A"— synchronous, runs immediatelyprocess.nextTick(...)— registered as a VIP microtaskPromise.resolve().then(...)— registered as a regular microtasksetTimeout(...)— registered as a macrotask"E"— synchronous, runs immediately- Call stack is empty — VIP microtasks run first →
"B" - Regular microtasks run next →
"C" - Macrotask runs last →
"D"
process.nextTick()is not actually part of the event loop phases. It runs after the current operation completes, before the event loop continues — making it the highest priority async operation in all of Node.js.
📋 The Updated Priority Order
With process.nextTick() in the picture, here's the complete priority order in Node.js:
| Priority | What | Type |
|---|---|---|
| 1st | Synchronous code | Call stack |
| 2nd | process.nextTick() | VIP microtask |
| 3rd | Promise .then() / await | Regular microtask |
| 4th | Macrotasks | setTimeout, I/O callbacks, etc. |
The browser doesn't have process.nextTick() — it's Node.js only. Everything else works the same way.
🤔 When Would You Actually Use process.nextTick()?
process.nextTick() is used when you need something to run after the current operation but before anything else — including Promises.
A common real world use case is deferring a callback until after an object is fully initialised:
class DataLoader {
constructor() {
// We want to emit 'ready' after the constructor finishes
// but process.nextTick ensures it runs before any I/O or timers
process.nextTick(() => {
this.emit('ready');
});
}
}
Without process.nextTick(), 'ready' might fire before the caller has had a chance to set up a listener for it. By deferring it with process.nextTick(), you guarantee the constructor finishes first — but the event still fires before anything else in the queue.
🧩 The Complete Node.js Picture So Far
Synchronous code
↓
process.nextTick() ← VIP microtask, Node.js only
↓
Promise .then() / await ← regular microtask
↓
I/O callbacks ← file reads, network requests complete here
↓
[more microtasks if added inside I/O]
↓
setTimeout / setInterval ← timers phase
We're not quite done — there's one more Node.js addition that belongs in this diagram. That's setImmediate(), and it gets its own dedicated post next.
✅ Key Takeaways
- Node.js lets you run JavaScript outside the browser — same language, slightly different event loop
- I/O means your program talking to the outside world — file reads, network requests, database calls
- I/O and Promises are two separate moments — I/O happens outside JavaScript, the Promise resolves after
process.nextTick()is a VIP microtask — runs before even Promises, Node.js only- The priority order in Node.js is: synchronous →
process.nextTick()→ Promises → macrotasks
You now see Node.js not as a mystery, but as JavaScript with a few extra lanes on the same highway — same rules, same event loop, just a couple of powerful additions.
🔮 What's Next
In Post 4, we complete the Node.js event loop picture with setImmediate() — what it is, how it fits after I/O, and why its position in the event loop makes it behave differently from setTimeout depending on where you use it.
This is Part 3 of a 5-part series on the JavaScript Event Loop.

