Node.js
Node.js is a JavaScript runtime built on Chrome's V8 engine that runs JavaScript outside the browser — on the server. Its event-driven, non-blocking I/O model makes it excellent for I/O-bound work like APIs, real-time apps, and tooling, and it lets you use one language across the whole stack.
The mental model that matters most: Node is single-threaded with an event loop. It handles thousands of concurrent connections not by spawning threads, but by never blocking — kicking off I/O and processing results via callbacks/Promises when they're ready. See Async JavaScript for the patterns.
TL;DR
- A JavaScript runtime with an event-driven, non-blocking I/O model.
- Single-threaded event loop — don't block it with synchronous work.
- Use async/await for asynchronous operations; handle rejections.
- Leverage the npm ecosystem; use streams for large data and cluster for multi-core.
Quick Example
A minimal HTTP server — Node's "hello world":
Modules
CommonJS (traditional) and ES Modules (modern)
Built-in modules: fs, path, http, os, crypto, stream, events, child_process, util.
Asynchronous Programming
File System & Paths
HTTP Server with Routing
In practice most apps use a framework (Express, Fastify, NestJS, Hono) over the raw http module.
Streams
Streams process data incrementally — essential for large files without loading everything into memory:
Events, Process & Child Processes
Performance & Clustering
Node is single-threaded, so to use multiple cores, run multiple processes (the cluster module or a process manager like PM2), or offload CPU-heavy work to worker threads:
Best Practices
- Never block the event loop — avoid synchronous I/O (
readFileSync) and heavy CPU in request handlers; use worker threads. - Handle every rejection and add
process.on('unhandledRejection', …)as a safety net. - Stream large data instead of buffering it all in memory.
- Clean up timers, listeners, and connections; shut down gracefully on
SIGTERM. - Pin Node versions (nvm/
.nvmrc) and audit dependencies.
Common Mistakes
Blocking the event loop
Unhandled promise rejections
FAQ
How does Node handle concurrency if it's single-threaded?
The event loop. Node offloads I/O (network, disk) to the OS and libuv, then runs your callbacks/Promises when results are ready — so one thread juggles thousands of connections without blocking. CPU-bound work is the exception: it does block the loop, so move it to worker threads or separate processes.
CommonJS or ES Modules?
ES Modules (import/export) are the modern standard and work across the ecosystem; enable them with "type": "module" or .mjs. CommonJS (require/module.exports) is still everywhere in existing code and fully supported. New projects generally use ESM.
How do I use multiple CPU cores?
Node runs one event loop per process, so scale across cores by running multiple processes — the cluster module (workers sharing a port), a process manager like PM2, or container replicas behind a load balancer. For CPU-heavy computation within a process, use worker threads.
Why shouldn't I use synchronous APIs like readFileSync?
They block the single event-loop thread, so while one request reads a file synchronously, every other request waits. Use the async (Promise) versions in servers. Sync APIs are fine only in startup scripts or CLIs where nothing else is waiting.
Related Topics
- JavaScript — The language
- Async JavaScript — Promises and the event loop
- REST API Design — Building Node APIs (Express, etc.)
- TypeScript — Typing Node apps
- Microservices — Node services at scale