HTTP & Networking
Node.js as a networking platform
Section titled “Node.js as a networking platform”One of Node.js’s defining strengths is its first-class networking support baked directly into the runtime. Before frameworks like Express or Fastify existed, developers wrote HTTP servers using nothing but the built-in node:http module — and that module is still the engine under every framework today.
This module teaches you to work with HTTP at the level that matters: the request/response cycle, routing, headers, status codes, and outbound fetching. By the end you will understand what every framework does under the hood.
What this module covers
Section titled “What this module covers”| Lesson | Topic |
|---|---|
| HTTP Server | http.createServer, status codes, headers, res.end |
| Routing | Manual routing on req.method and req.url |
| Outbound Requests | Global fetch, JSON, error handling |
| JSON API | Parse body, route, respond with JSON |
| Production Server | Error handling, limits, timeouts, graceful shutdown |
The request lifecycle
Section titled “The request lifecycle”Every request follows the same shape, no matter which lesson below you are in: Node parses the incoming bytes into a req object, your callback runs, you write a res, and the connection either closes or waits for the next request:
flowchart TD
A["Client sends an HTTP request"] --> B["Node parses headers into an IncomingMessage (req)"]
B --> C["The request listener callback runs"]
C --> D["Handler reads the body, if any (data/end events)"]
D --> E["Handler calls res.writeHead(status, headers)"]
E --> F["Handler calls res.end(body)"]
F --> G{"Connection: keep-alive?"}
G -->|yes| H["Socket stays open, waits for the next request"]
G -->|no| I["Socket closes"]
Later lessons in this module fill in the sharp edges of this diagram: what happens if step D never finishes (body limits), what happens if step E or F is skipped or repeated (error listeners, ERR_HTTP_HEADERS_SENT), and how “waits for the next request” is bounded by real timeouts.
A minimal server — right now
Section titled “A minimal server — right now”No npm install, no framework, no config files. This is a complete Node.js HTTP server:
Needs the Node.js runtime — open in StackBlitz to run.
Three lines of logic — that is all it takes. The rest of this module unpacks each part.
Mental Model
Section titled “Mental Model”Think of node:http as the actual wire-protocol implementation, and every framework — Express, Fastify, Hono, Koa — as ergonomics layered on top of the same req/res objects from the diagram above. A framework’s app.get('/path', handler) is a router that eventually calls res.writeHead() and res.end() for you; a middleware chain is just a sequence of functions sharing the same req/res. Nothing a framework does is magic — it is all reachable with the module you already have installed.
Trade-offs
Section titled “Trade-offs”Writing directly against node:http gives you full control and zero dependencies, but it also means you own every edge case this module covers: body size limits, malformed input, timeouts, graceful shutdown. A framework buys productivity — routing, middleware, validation helpers — by making reasonable choices for those edge cases on your behalf. Neither is “correct”: a small internal tool might be better off with three routes and no framework at all, while a public-facing API benefits from a framework’s tested defaults. Either way, understanding the raw model means a framework’s behavior is never a black box.
Common Misconceptions
Section titled “Common Misconceptions”- “You need Express to build a real HTTP server.”
node:httpalready is a real, production-capable HTTP server — Express adds routing conventions and middleware, not HTTP itself. - “
http.createServerhandles error cases for you.” It does not. Forgetting an'error'listener, a body size limit, or a shutdown handler are all silent gaps you have to fill yourself — covered later in this module. - “A demo that works once is production ready.” A demo proves the happy path. The rest of this module is about the paths that are not happy: bad input, slow clients, a server that needs to restart.
Reading AI-generated code
Section titled “Reading AI-generated code”AI-generated node:http servers reliably nail the happy path — a route that responds correctly — and just as reliably skip the response lifecycle details that only show up under real traffic, like actually finishing every response.
🐛 Spot the bug
const http = require('node:http');
const server = http.createServer(function (req, res) {if (req.url === '/health') { res.writeHead(200, { 'Content-Type': 'text/plain' }); // TODO: send the body once we decide on a format} else { res.writeHead(404, { 'Content-Type': 'text/plain' }); res.end('Not found');}});
server.listen(3000);Show the answer
The /health branch calls res.writeHead() but never calls res.end(). Node does not close the response for you — the client is left waiting until it eventually times out on its own. The fix is the same one-liner every branch needs: make sure every code path that starts a response also calls res.end() (or res.destroy() if you are deliberately aborting it).