Node.js, part 7: HTTP/2 in core — multiplexing, headers, and the end of the connection pool hack
Part 7from the Node.js series · 24 parts in all
HTTP/1.1's workaround for concurrency is to open several TCP connections and keep them
alive, because one connection carries one request at a time. HTTP/2 multiplexes streams over
a single connection, compresses headers, and (originally) pushed resources. Node grew a
first-class http2 module — part 7 is what changes in your code and what does
not.
A server is close to the HTTP/1 one
const http2 = require('http2');
const { readFileSync } = require('fs');
const server = http2.createSecureServer({
key: readFileSync('localhost-key.pem'),
cert: readFileSync('localhost-cert.pem'),
});
server.on('stream', (stream, headers) => {
// headers[":method"], headers[":path"] carry what used to be separate fields
stream.respond({ ':status': 200, 'content-type': 'application/json' });
stream.end(JSON.stringify({ path: headers[':path'] }));
});
server.listen(8443);
Two structural differences are visible here. HTTP/2 is encrypted in practice
— browsers only speak it over TLS, so there is a certificate even locally. And each request is
a stream, which is why the handler is on 'stream' rather than
'request': many streams share one socket, interleaved.
What multiplexing changes downstream
- No more connection pool. A single client connection can carry hundreds of concurrent requests, so "keep-alive agent with maxSockets" stops being a tuning knob.
- Head-of-line blocking, but smaller. One lost TCP packet still stalls every stream on that connection. HTTP/3 over QUIC is what removes that, and it is a different protocol again.
- Server push was the idea that did not survive. It sounded like a performance win and proved hard to use well; browsers are removing it. Multiplexing is the part that stuck — plan for it and ignore push.
The practical recommendation
Terminate HTTP/2 at your proxy (nginx, a cloud load balancer) and let Node speak plain
HTTP/1.1 on the inside, unless you specifically need server-to-server multiplexing or
streaming. You get the protocol benefits for browsers without teaching every internal
service a new API — and http2.createSecureServer supports an
allowHTTP1: true option precisely so one listener can serve both. Next:
dependency hygiene, the least glamorous thing on this list and the one that keeps you out of
incidents.