3 minutes
HTTP/2 & QUIC Support: Speeding Up Node.js Servers
Summary
Node.js v18 builds in HTTP/2 via the core http2
module and ships experimental QUIC (HTTP/3) support behind a flag. HTTP/2 brings multiplexed streams, header compression, and server push to your apps, while QUIC leverages UDP, 0-RTT handshakes, and improved loss recovery for lower-latency connections (nodejs.org, nodejs.org).
1. Introduction
HTTP/2, standardized in 2015, addresses HTTP/1.1’s head-of-line blocking by allowing multiple request/response pairs over a single TCP connection using multiplexing and HPACK header compression (stackoverflow.com, devcrud.com). HTTP/3 (QUIC) moves this model to UDP, adding built-in TLS 1.3, 0-RTT reconnects, and connection migration for mobile clients (javascript-conference.com). Before Node.js v18, you had to rely on reverse proxies (like Nginx, Envoy) or external modules to get HTTP/2 or QUIC support.
2. HTTP/2 in Node.js v18
2.1 Enabling HTTP/2
Require the built-in module or import in ESM:
// CommonJS
const http2 = require('node:http2');
// ESM
import http2 from 'node:http2';
For a secure server, use createSecureServer
with TLS certs:
import fs from 'fs';
import http2 from 'node:http2';
const server = http2.createSecureServer({
key: fs.readFileSync('key.pem'),
cert: fs.readFileSync('cert.pem'),
});
server.listen(8443);
2.2 Key Features
- Multiplexing: Multiple HTTP streams share a single TCP connection, eliminating head-of-line blocking at the HTTP layer (stackoverflow.com).
- HPACK Compression: Headers are compressed efficiently, reducing overhead on repeated headers (nodejs.org).
- Server Push: Servers can proactively send resources to clients before an explicit request, useful for linked assets like CSS or JS (blog.risingstack.com).
2.3 Example
import fs from 'fs';
import http2 from 'node:http2';
const server = http2.createSecureServer({
key: fs.readFileSync('key.pem'),
cert: fs.readFileSync('cert.pem')
});
server.on('stream', (stream, headers) => {
stream.pushStream({ ':path': '/style.css' }, (err, pushStream) => {
pushStream.end('body { background: #fafafa }');
});
stream.end('<h1>Hello HTTP/2</h1>');
});
server.listen(8443);
3. QUIC (HTTP/3) Experimental Support
3.1 Under the Hood
QUIC support in Node.js v18 is experimental and lives behind the --experimental-quic
flag. It uses a user-space QUIC implementation built atop OpenSSL/QuicTLS, combining UDP transport, TLS 1.3, and multiplexed streams in one protocol (nearform.com).
3.2 Enabling QUIC
Start your app with QUIC enabled:
node --experimental-quic index.js
For fetch()
over QUIC, also enable the experimental fetch API:
node --experimental-quic --experimental-fetch index.js
3.3 Example Snippet
import { createQuicSocket } from 'node:net';
(async () => {
const socket = createQuicSocket({ endpoint: { address: '0.0.0.0', port: 4433 } });
await socket.listen();
for await (const session of socket) {
session.on('stream', stream => {
stream.write('HTTP/3 Hello World');
stream.end();
});
}
})();
4. Performance Tuning & Metrics
- 0-RTT Handshakes: QUIC’s 0-RTT feature lets returning clients resume connections with zero round trips, drastically reducing latency on reconnections (javascript-conference.com).
- TLS Session Reuse: Both HTTP/2 and QUIC benefit from TLS session tickets for fast reconnects (linkedin.com).
- Latency & Throughput: Benchmark HTTP/1.1, HTTP/2, and QUIC using tools like
wrk
orhey
to compare RTTs, requests/sec, and CPU usage (linkedin.com).
5. Pitfalls & Best Practices
- API Maturity: The QUIC API is experimental and subject to change; avoid using it in production until stable APIs land (nearform.com).
- Certificate Management: Ensure ALPN negotiation includes
h3
and fallback toh2
orhttp/1.1
for clients that don’t support QUIC (nodejs.org). - Monitoring & Fallback: Use health checks and metrics to detect QUIC failures and gracefully fallback to HTTP/2 to maintain availability (javascript-conference.com).
6. Full Walkthrough
Create self-signed certs:
openssl req -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 365 -out cert.pem
Implement both HTTP/2 and QUIC servers as shown above.
Benchmark with
wrk
:wrk -t4 -c100 -d20s https://localhost:8443 wrk -t4 -c100 -d20s quic://localhost:4433
Compare latency percentiles and requests/sec in the results.
7. Conclusion & Further Reading
HTTP/2 in Node.js v18 brings first-class support for multiplexing, header compression, and server push without extra proxies, while experimental QUIC unlocks UDP-based, low-latency connections with built-in TLS and 0-RTT. Monitor performance and use fallback strategies to keep your apps resilient.
Further Reading
- Node.js HTTP/2 docs: https://nodejs.org/api/http2.html (nodejs.org)
- Node.js QUIC docs: https://nodejs.org/api/quic.html (nodejs.org)
- A QUIC Update for Node.js: https://nearform.com/insights/a-quic-update-for-node-js/ (nearform.com)