Course:Node.js & Express/
Lesson

For most of the web's early history, JavaScript had one job: make web pages interactive in the browser. Every server-side application was written in a different language, PHP, Java, Python, Ruby. Node.js, released in 2009 by Ryan Dahl, broke that rule by lifting JavaScript out of the browser and placing it directly on the server, letting you write your entire stack in one language.

How Node.js actually runs your code

At its core, Node.js wraps Google's V8What is v8?Google's JavaScript engine that compiles JavaScript to native machine code - it powers both Chrome and Node.js. engine, the same engine powering Chrome, inside a runtimeWhat is runtime?The environment that runs your code after it's written. Some languages need a runtime installed on the machine; others (like Go) bake it into the binary. that adds server-side APIs. V8 compiles your JavaScript into native machine code before executing it, which is why Node.js is far faster than older interpreted runtimes.

Underneath V8, a C++ library called libuv handles all the operating-system-level work: reading files, opening network sockets, and talking to databases. This is the piece that makes Node.js's famous non-blocking model possible.

┌─────────────────────────────────────┐
│           Your JavaScript code      │
├─────────────────────────────────────┤
│  Node.js core modules (fs, http…)   │
├─────────────────────────────────────┤
│  C++ bindings (libuv, V8, OpenSSL)  │
├─────────────────────────────────────┤
│  Operating system                   │
└─────────────────────────────────────┘
02

The event loopWhat is event loop?The mechanism that lets Node.js handle many operations on a single thread by delegating slow tasks and processing their results when ready.: Node's secret weapon

Traditional web servers (Apache, classic Java EE) create a new operating-system thread for every incoming request. Threads are expensive, they consume memory and the OS has to switch between them constantly. Under heavy load, a server with thousands of threads starts to grind.

Node.js takes a different approach. It runs on a single thread, and instead of waiting for slow operations to finish, it delegates them and keeps moving. When the operation completes, a callbackWhat is callback?A function you pass into another function to be called later, often when an operation finishes or an event occurs. (or a resolved PromiseWhat is promise?An object that represents a value you don't have yet but will get in the future, letting your code keep running while it waits.) brings the result back.

Here is the same work done two ways:

// Blocking - the thread freezes until the file is fully read
const data = fs.readFileSync('report.txt', 'utf8');
console.log(data);
console.log('This prints after the file is read');
// Non-blocking - Node starts reading and immediately moves on
fs.readFile('report.txt', 'utf8', (err, data) => {
  if (err) throw err;
  console.log(data); // prints whenever the file is ready
});
console.log('This prints right away, before the file is read');

Think of it like a good waiter at a busy restaurant. Instead of standing at one table until the kitchen delivers every dish, they take an order, pass it to the kitchen, and immediately move to the next table. When the kitchen calls out that an order is ready, they pick it up and deliver it. One waiter (one thread), many tables (many requests), all moving forward at once.

The event loop phases

The event loop cycles through a series of queues in a fixed order. The ones you will encounter most often are:

  1. Timers: runs callbacks scheduled by setTimeout and setInterval
  2. I/O callbacks: handles completed I/O operations (file reads, network responses)
  3. Poll: retrieves new I/O events and waits if the queue is empty
  4. Check: runs setImmediate callbacks
  5. Close callbacks: cleans up things like closed sockets
The event loop only moves to the next phase after the current phase's callback queue is empty. A single callback that does heavy CPU work will block the loop and make every other request wait, this is why CPU-intensive code is problematic in Node.js.
03

Non-blocking I/OWhat is non-blocking i/o?A pattern where your program starts an operation like reading a file, moves on to other work immediately, and comes back to handle the result when ready. in practice

The non-blocking model shines when your application spends most of its time waiting: waiting for a database to return rows, waiting for a third-party APIWhat is api?A set of rules that lets one program talk to another, usually over the internet, by sending requests and getting responses. to respond, waiting for a file to be read from disk. In all of those cases, Node can be handling other requests during the wait.

const http = require('http');

http.createServer((req, res) => {
  // Imagine this is a database call that takes 50ms
  simulateDbQuery((err, result) => {
    res.end(JSON.stringify(result));
  });
  // Node does NOT block here - it handles the next request immediately
}).listen(3000);
04

Where Node.js fits, and where it does not

Understanding when to reach for Node.js saves you a lot of pain.

Strong fits

  • RESTWhat is rest?An architectural style for web APIs where URLs represent resources (nouns) and HTTP methods (GET, POST, PUT, DELETE) represent actions on those resources. and GraphQLWhat is graphql?A query language for APIs where clients specify the exact shape of data they need in a single request, avoiding over-fetching and under-fetching. APIs
  • Real-time applications (chat, live dashboards, multiplayer games via WebSockets)
  • Streaming (audio, video, large file uploads)
  • MicroservicesWhat is microservices?An architecture where an application is split into small, independently deployed services that communicate over the network, each owning its own data. and serverlessWhat is serverless?A hosting model where individual functions run on demand and the platform handles all server management, scaling, and uptime for you. functions
  • Developer tooling (CLIs, build scripts, task runners)

Poor fits

  • CPU-intensive work: image manipulation, video transcoding, machine learning inference
  • Heavy numerical computation (scientific simulations, data crunching)
If you need CPU-heavy work alongside Node, the solution is to offload it to a separate worker process or a dedicated service, not to do it on the event loop thread.
05

The JavaScript-everywhere advantage

One of the most practical benefits of Node.js is that your team speaks one language across the entire stack. You can share validation logic, data-transformation utilities, and even type definitions between the browser bundleWhat is bundle?A single JavaScript file (or set of files) that a build tool creates by combining all your source code and its imports together. and the server.

LayerPopular choices
Frontend frameworkReact, Vue, Svelte
Backend frameworkExpress, Fastify, NestJS
Full-stack frameworkNext.js, Nuxt, SvelteKit
MobileReact Native
DesktopElectron
CLI toolingCommander, Yargs

All of these run on or alongside Node.js, and all of them let you write JavaScript (or TypeScript) from top to bottom.

06

Quick reference

ConceptWhat it means
V8The JavaScript engine; compiles JS to native machine code
libuvC++ library that provides the event loop and async I/O
Event loopThe mechanism that lets one thread handle many operations
Non-blocking I/OStarting an operation without waiting for it to finish
CallbackA function called when an async operation completes
Single-threadedOne main thread, no thread-per-request overhead