This is a simulation. Every request, timer, and query below is illustrative — nothing here makes a real network call.
The call stack, blocking, timers, and microtasks — as a plain script.
Before Node adds anything, plain JavaScript already has rules worth knowing cold: one call stack, one thing running at a time, and a strict pecking order between timers and microtasks. This level treats every example as a script, not a server — no pools, no cluster, no HTTP — so the only thing on screen is the call stack and two small queues.
libuv, the six event-loop phases, nextTick, timers, and the threadpool.
Level 1 was plain JavaScript. This level is what Node — really, the libuv library underneath it — adds on top: a fixed cycle of event-loop phases, an extra nextTick queue that jumps ahead of microtasks, a firm ordering between timers and setImmediate, and a small pool of background threads for the handful of things that genuinely need one.
Sequential vs concurrent, CPU-bound vs I/O-bound, and how to offload real work.
With the event loop's mechanics in place, this level is about writing async code that actually uses them well: when Promise.all helps and when it doesn't, why await alone can't fix CPU-bound work, and where worker_threads and child_process fit in.
The full request flow, concurrency between requests, and scaling out.
This level puts it all together: a real request's path from socket to response, what happens when many requests overlap, where pools and blocking handlers bite, and how cluster trades shared memory for parallelism. It ends by handing you to the Lab, where every request kind and scenario from this path is available for free play.