Node.js · Getting Started

Node.js Architecture

Node runs your JavaScript on a single thread, yet handles thousands of connections. The secret is the event loop: Node hands slow work to the system and gets back to your code when it is done.

Beginner 5 min Lesson 2 of 37Examples target Node.js 22 LTS.
Before you start:Introduction to Node.js
0/37 in Node.js
On this page · 5 min · Beginner

Learning objectives#

  • Describe V8, libuv and the event loop
  • Predict the order of sync code, microtasks and timers
  • Explain non-blocking I/O
  • Recognise and avoid blocking the event loop

Explanation#

V8 executes your JavaScript. libuv provides the event loop and asynchronous I/O (network, files, timers), using the operating system and a small thread pool.

Your code runs on one main thread with a call stack. When you start I/O (read a file, query a database), Node registers a callback and moves on.

When the I/O finishes, its callback is queued. The event loop picks queued callbacks one at a time whenever the call stack is empty.

Order: synchronous code first, then microtasks (resolved promises; process.nextTick is a similar high-priority queue), then macrotasks like timers and I/O callbacks.

Blocking code (a long loop, readFileSync on a big file, heavy JSON.parse) keeps the stack busy, so no other callback — no other user — can run. Keep handlers short and async.

Syntax#

Text Illustrative
your code ──► call stack (V8, single thread)
   │ async work (fs, net, timers)
   ▼
libuv ── OS / thread pool ── done ──► callback queue ──► event loop ──► call stack

Code example: Predict the order of execution#

JavaScriptevent-loop.js Illustrative
console.log('1. start');


setTimeout(() => console.log('5. timeout (macrotask)'), 0);


Promise.resolve().then(() => console.log('4. promise (microtask)'));


console.log('2. end of synchronous code');


// A blocking loop delays everything that is waiting
const start = Date.now();
while (Date.now() - start < 200) { /* busy for 200 ms */ }
console.log('3. after 200 ms of blocking work');
Expected output
1. start
2. end of synchronous code
3. after 200 ms of blocking work
4. promise (microtask)
5. timeout (macrotask)

This example is illustrative. Copy or download it and run it in your own environment; the expected output is shown above.

Step-by-step explanation#

  1. All synchronous lines run first, top to bottom — including the 200 ms busy loop.
  2. Only when the call stack is empty does Node process queued work.
  3. The promise callback (a microtask) runs before any timer.
  4. The timeout callback runs last, even with a 0 ms delay — and it waited the full 200 ms of blocking.

Real-world use case#

An API got slow for everyone whenever one user downloaded a report: the report was built with a synchronous loop over 200,000 rows. Moving it to a worker thread kept the event loop free and response times flat.

Common mistakes#

Thinking setTimeout(fn, 0) runs immediately

It runs after the current code and all microtasks finish.

Sync APIs in servers

fs.readFileSync, crypto.pbkdf2Sync and big loops block every request. Use the async versions.

“Node is single-threaded, so it can’t do parallel work”

Your JS runs on one thread, but I/O happens in parallel in the OS and thread pool; worker_threads add CPU parallelism.

Best practices#

  • Never block the event loop in request handlers
  • Prefer async APIs everywhere
  • Move CPU-heavy tasks to worker threads or queues
  • Measure event-loop delay in production

Remember this#

One JS thread + event loop + libuv for I/O.

Order: sync code → microtasks (promises) → timers/I/O.

Blocking the loop blocks every user.

Practice exercise#

Your task: Predict the output order: console.log("A"); setTimeout(() => console.log("B")); Promise.resolve().then(() => console.log("C")); console.log("D");

Need a hint?
Synchronous first, then microtasks, then timers.
Show solution
JavaScript Illustrative
console.log('A');
setTimeout(() => console.log('B'));
Promise.resolve().then(() => console.log('C'));
console.log('D');
// A
// D
// C
// B

Mini quiz#

Node.js Architecture quizPredict the output Question 1 of 3

What is the output order?

setTimeout(() => console.log('T'), 0);
Promise.resolve().then(() => console.log('P'));
console.log('S');
Score so far: 0/0

Want more? Practise all Node.js MCQs · Node.js interview questions

My notes#

Saved in this browser.

Progress is saved in this browser. Sign in to sync.