Open this lesson in your favourite AI. It'll walk you through the why, explain the demo, and quiz you on the try-it list.
Node.js is JavaScript glued onto V8 (Google's JS engine) plus libuv (a C library that provides an event loop and async I/O across OS APIs). Understanding that 'Node is single-threaded' is half-true (your JS runs on one thread, but the libuv worker pool handles disk I/O, DNS, crypto in real OS threads) is the foundational mental model. Get this wrong and you'll be confused why a CPU-heavy loop blocks all your requests but reading 100 files concurrently doesn't.
Node.js achieves concurrency through a single-threaded event loop that processes I/O callbacks rather than blocking threads — a design that makes it efficient for high-throughput I/O workloads but terrible for CPU-intensive operations that block the loop. Under load, every async operation you initiate gets queued as a callback and the event loop processes them one at a time between I/O interrupts. Understanding this model explains why a single slow synchronous operation can freeze your entire server and why Node.js's strength is concurrent I/O, not parallel computation.
node -p "process.versions". Note the V8 and libuv versions — these change with Node major releases.node), type os.cpus().length and os.freemem(). The OS APIs are right there in stdlib.node --help and skim the --enable-source-maps and --watch flags. We'll use these next.Use these three in order. Each builds on the one before.
In one paragraph, explain what Node.js *is* — JS engine + what? And what does 'single-threaded' really mean for my code?
Walk me through libuv's thread pool: which Node operations use it (fs, dns, crypto), how do I see its size (UV_THREADPOOL_SIZE), and what happens if I exhaust it?
On a CPU-bound workload (image transcoding, hashing), how do I escape the single JS thread without giving up? Compare worker_threads, child_process, and `cluster`.
// proof that JS is single-threaded but I/O isn't:
import { readFile } from "node:fs/promises";
console.time("100 files");
const tasks = Array.from({ length: 100 }, (_, i) =>
readFile(`/etc/hosts`).then(() => i),
);
await Promise.all(tasks);
console.timeEnd("100 files"); // ~few ms — libuv ran them in parallel
// vs CPU-bound (blocks):
console.time("cpu");
let n = 0;
for (let i = 0; i < 1e9; i++) n++;
console.timeEnd("cpu"); // ~1+ sec — your JS thread is monopolized
// install + check version:
$ nvm install 22 # or volta install node@22
$ node --version
v22.4.0
$ node -p "process.versions"
{ node: '22.4.0', v8: '12.4', uv: '1.48.0', ... }node main.js