In short
Node runs your JavaScript on one thread, yet a single server juggles thousands of connections. The event loop is how, and it decides the exact order your callbacks run in.
The mechanism that lets single-threaded Node.js handle thousands of concurrent connections by delegating I/O work and processing callbacks as they complete, instead of blocking.

Think of it like this
The single cashier's rounds
One cashier, three baskets: 'due now', 'replies received', 'do right after'. She goes round them in the same order, one slip at a time. Urgent slips are handled the moment she finishes the current one, before she moves on. That round is the event loop.
Watch it happen
One turn of the event loop
1/7Your script runs top to bottom first. setTimeout, setImmediate and fs calls only schedule work for later.
The big ideas
What you need to know
One thread for callbacks
Only one callback runs at a time. A long synchronous loop freezes every other request until it finishes.
Microtasks jump the queue
process.nextTick and promise callbacks run before the loop moves to its next phase.
0 ms doesn't mean now
setTimeout(fn, 0) runs on a later turn of the loop, after the current code and all microtasks.
The loop knows when to stop
When no timers, sockets or pending I/O are left, the loop ends and the process exits.
See it in code
Walk through the code
1// order.cjs (run: node order.cjs)2const fs = require("node:fs");3 4console.log("1 sync");5setTimeout(() => console.log("timeout"), 0);6setImmediate(() => console.log("immediate"));7Promise.resolve().then(() => console.log("3 promise"));8process.nextTick(() => console.log("2 nextTick"));9 10fs.readFile(__filename, () => {11 setTimeout(() => console.log("io: timeout"), 0);12 setImmediate(() => console.log("io: immediate")); // always first here13});1/4Synchronous code always runs first, before any callback.
Output starts 1 sync, 2 nextTick, 3 promise. At the top level, timeout and immediate may swap between runs; inside an I/O callback, setImmediate always wins.
Save yourself the pain
Common mistakes
Oops
Running a heavy loop, like hashing a million strings, inside a request handler.
Do this instead
That blocks the loop and every user waits. Move heavy CPU work to worker_threads or a background job queue.
Oops
Using setTimeout(fn, 0) expecting fn to run immediately.
Do this instead
It runs on a later turn. If you need it right after the current code, use queueMicrotask, or just call the function.
Your mission
Predict the order
Quick check
In a CommonJS file, a resolved Promise's .then and a process.nextTick are both scheduled in the main script. Which logs first?
Go deeper
- 1Log the order of `setTimeout`, `Promise.then` and synchronous code to see the event loop phases.
- 2Learn the difference between the microtask queue (Promises) and macrotask queue (setTimeout).
- 3Understand why a long synchronous computation blocks the entire event loop.
More topics at this stop
Stuck on this topic? Ask an Insider
Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.