Skip to content
C Codeloom
Node.js

What Is Node.js? JavaScript Outside the Browser

A clear introduction to Node.js — the V8 engine, the event loop, non-blocking I/O, the npm ecosystem, and when Node is the right runtime for your project.

·9 min read · By Yash Kesharwani
Beginner 10 min read

What you'll learn

  • What Node.js actually is — and what it is not
  • How the V8 engine and the event loop work together
  • Why single-threaded, non-blocking I/O is a good fit for network servers
  • What npm is, and why the ecosystem is both an asset and a liability
  • When Node is the right runtime — and when something else fits better

Prerequisites

  • A basic familiarity with JavaScript — see What Is JavaScript?
  • Comfort opening a terminal

For the first fifteen years of its life, JavaScript only ran inside web browsers. In 2009, a developer named Ryan Dahl took the JavaScript engine out of Google Chrome, added a way to read files and open network sockets, and called the result Node.js. That decision turned JavaScript into a general-purpose backend language and changed the shape of the web industry.

This post explains what Node is, how it works, and when you should reach for it.

If you are new to JavaScript itself, start with What Is JavaScript? first.

What Node.js actually is

Node.js is a runtime: a program that takes JavaScript source code and runs it. The browser is also a runtime, but with a very different toolbox — the browser gives you the DOM, fetch, localStorage, and so on. Node gives you the file system, network sockets, child processes, streams, and other capabilities a server-side program needs.

Two pieces sit at the heart of Node:

  • V8. Google’s JavaScript engine — the same one that powers Chrome. V8 parses your code and compiles it to fast native machine code.
  • libuv. A C library that provides an event loop and a thread pool for asynchronous I/O. This is the piece that lets Node do many things at once without spawning a thread per request.

When you run node server.js, V8 executes your script and libuv handles the I/O behind the scenes. You write idiomatic JavaScript; the runtime takes care of the heavy lifting.

The event loop, in plain language

The single most-discussed feature of Node is the event loop. It deserves a clear explanation.

A traditional server creates one thread (or process) per incoming request. If a request is waiting for the database to respond, that thread sits idle, consuming memory. Under heavy load you run out of threads.

Node takes a different approach. There is one main thread that runs your JavaScript. When your code starts an I/O operation — reading a file, querying a database, calling an HTTP API — Node hands the operation off to libuv and immediately returns to running other JavaScript. When the I/O finishes, libuv puts a callback on a queue. The event loop picks it up and runs it.

// This does NOT block. The event loop is free to handle
// other requests while the file is being read.
fs.readFile('big.json', (err, data) => {
  console.log('done reading');
});

console.log('this prints first');

The result: a single Node process can comfortably handle tens of thousands of open connections at once, provided each one is mostly waiting on I/O. That is exactly what a chat server, an API gateway, or a websocket service looks like.

The catch is the flip side: if your JavaScript itself takes a long time to run, nothing else can happen. A 500ms CPU-bound loop blocks every other request on the server for 500ms. We’ll come back to that.

npm: the ecosystem

npm (Node Package Manager) ships with Node and connects you to the npm registry — the largest collection of open-source code in any language, with well over two million packages. Need to parse a CSV, validate an email, talk to AWS, render a PDF? There is a package for it.

npm init -y
npm install express

Two lines, and you have a fully fledged web framework available.

The strength of the ecosystem is also its weakness. Many packages are tiny, many depend on many others, and the dependency tree of a real application can run to hundreds of packages. Modern Node tooling (lockfiles, audit tools, alternative registries like pnpm and bun) exists to manage that complexity. As a beginner, just be aware that adding a package is not free — every dependency is code you are implicitly trusting.

Where Node fits

Node is an excellent choice for:

  • HTTP APIs. REST and GraphQL backends are Node’s bread and butter. Frameworks like Express, Fastify, and Hono are mature and battle-tested.
  • Real-time services. Chat, presence, collaborative editing, multiplayer games — anything built on websockets — benefits from Node’s I/O model.
  • Frontend tooling. Vite, webpack, esbuild, TypeScript, Prettier, ESLint, and most of the build pipeline for modern frontends run on Node. If you build for the web, you already use Node whether you realise it or not.
  • CLI tools. A surprising amount of developer tooling is written in Node because npm makes distribution easy and the language is familiar.
  • Edge functions and serverless. Cloudflare Workers, Vercel Functions, AWS Lambda — JavaScript runtimes are first-class on every major edge platform.
  • Glue scripts. Talking to APIs, transforming JSON, automating small tasks. Node competes directly with Python here.

Where Node is not the right tool

Be honest about the tradeoffs:

  • CPU-heavy work — image processing, video encoding, large-scale numeric computation, machine learning training — is a poor fit. The single main thread becomes a bottleneck. Languages with real multi-threading (Go, Rust, Java) or specialised stacks (Python with NumPy / PyTorch) are usually better.
  • Long-running scientific or ML workflows. The data science ecosystem lives in Python and won’t move soon.
  • Hard real-time systems. Garbage-collected runtimes are a bad fit for guaranteed sub-millisecond response times.
  • Systems programming. Drivers, kernels, embedded firmware — use C, Rust, or Zig.

Node can offload CPU-heavy work to worker threads or child processes, but at that point you are working around the design rather than with it. Pick the right tool from the start.

Node vs Deno vs Bun

A quick note on alternatives, because you’ll see them mentioned.

  • Deno. Built by the same Ryan Dahl who created Node, with the goal of fixing early design mistakes — TypeScript out of the box, secure-by-default permissions, modern module system.
  • Bun. A newer runtime focused on speed, with a built-in bundler, test runner, and package manager. Largely Node-compatible.

Both are real, both are growing, but Node still has the deepest ecosystem and the largest hiring market. Learn Node first; pick up the others as needed.

A first Node program

You don’t need a framework to start. Here’s a complete HTTP server in fewer than ten lines of code.

// server.js
import { createServer } from 'node:http';

const server = createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('Hello from Node!\n');
});

server.listen(3000, () => {
  console.log('Listening on http://localhost:3000');
});

Save it as server.js and run:

node server.js

Open http://localhost:3000 in your browser. You’ll see Hello from Node! rendered as plain text. That is a complete web server — no framework, no build step, no configuration file. The same machinery you just saw scales to power production services serving millions of requests a day.

Try it yourself. If you don’t have Node installed yet, grab it from nodejs.org (pick the LTS version). Then save the snippet above as server.js, run node server.js, and visit localhost:3000. Once it works, change the response to return JSON instead of plain text:

res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ hello: 'world' }));

Hit the URL again. You’ve just written your first API.

What Node is not

A few clarifications that save confusion later:

  • Node is not a framework. Express, Next.js, NestJS are frameworks. Node is the runtime they run on.
  • Node is not just for “JavaScript developers.” A surprising amount of Node code is written by people whose primary language is something else; the runtime is good at being a polyglot’s glue language.
  • Node is not slow. V8 is one of the fastest dynamic-language runtimes ever built. Benchmarks vary, but for I/O-bound workloads Node frequently outperforms more “serious” stacks.
  • Node is not stalled. The release cadence is steady (a major version every six months, LTS every twelve), the language keeps gaining features (top-level await, native test runner, native fetch), and the ecosystem is healthy.

How Node fits with the rest of the stack

A typical modern web product looks like this:

  • A React or Astro frontend built using Node-based tooling (Vite, webpack)
  • A Node.js backend serving JSON over HTTP and websockets
  • A SQL database (Postgres, MySQL) holding the canonical state
  • Optional caches, queues, and search engines
  • Containerised with Docker, deployed to a cloud provider

Node sits in the middle layer — close to the database, close to the frontend, fast at moving JSON between the two.

Recap

You now know:

  • Node.js is a JavaScript runtime built on V8 plus libuv
  • The event loop lets a single thread juggle many concurrent I/O operations
  • npm is the ecosystem — vast, useful, and worth treating with care
  • Node excels at APIs, real-time services, tooling, and scripts
  • Node is not the right tool for CPU-heavy work, scientific computing, or systems programming

Next steps

If you haven’t installed Node yet, the Browser and Node setup post walks through it. After that, the natural next steps are picking a small web framework (Express or Fastify) and building a tiny JSON API on top of the HTTP server you just saw.

Questions or feedback? Email codeloomdevv@gmail.com.