HTTP Fundamentals Best Practices
A condensed summary of the 25 most important HTTP practices for Node.js backends - drawn from every page in this section.
-
Set
requestTimeouton every server: 30s is a sane default - HTTP Basics in Node. -
Set
headersTimeout>requestTimeout: Node 18+ enforces this relationship or connections break mid-request. -
Align
keepAliveTimeoutbelow proxy idle timeout: Prevents 502s during rolling deploys - Keep-Alive & Connection Limits. -
Reuse outbound
AgentwithkeepAlive: true: One TCP connection per downstream call wastes FDs and adds latency. -
Cap
maxSocketson outbound agents: Prevent a slow dependency from exhausting file descriptors. -
Set per-request timeouts on outbound HTTP:
req.setTimeout()or library timeout option on every call. -
Limit request body size: 1-10 MB for JSON APIs; reject early with 413 - Middleware Pattern.
-
Always call
res.end()exactly once: Hung responses are the most common raw HTTP bug. -
Return proper status codes: 201 for creates, 204 for deletes, 422 for validation - not everything is 200 or 500.
-
Set
Content-Typewith charset:application/json; charset=utf-8for international text. -
Enable
trust proxywith hop count, nottrue: SpoofedX-Forwarded-Forbypasses rate limits - Reverse Proxy Awareness. -
Register rate limiters after trust proxy: Otherwise every client appears as the load balancer IP.
-
Log client IP from
req.ip, not socket address: Audit and compliance require the real client behind the proxy. -
Terminate TLS at nginx/ALB/Cloudflare: Node speaks HTTP/1.1 internally unless gRPC needs h2 - HTTP/2 & HTTP/3 Considerations.
-
Disable
proxy_bufferingfor SSE streams: nginx buffers break real-time delivery. -
Normalize trailing slashes: Pick
/usersor/users/and redirect the other. -
Handle
OPTIONSfor CORS explicitly: Browsers preflight before POST with custom headers. -
Graceful shutdown on
SIGTERM:server.close()beforeprocess.exit- Kubernetes sends SIGTERM on pod delete. -
Health check without auth middleware:
/healthor separate port for probes. -
Stream large files, don't buffer:
createReadStream().pipe(res)for PDFs and exports. -
Use frameworks before 15 endpoints: Plain routing is fine for sidecars; public APIs need middleware conventions - Routing Without Frameworks.
-
Wrap async handlers in try/catch (raw HTTP): Express 5 does this automatically; raw
createServerdoes not. -
Raise
ulimit -nin production: Default 1024 file descriptors is not enough under load. -
Separate admin/internal ports: Metrics and health on
:8081, public API on:3000. -
Document proxy header contract in ADR: Which headers nginx sets, hop count, and timeout values - ops needs this during incidents.
FAQs
What is the single highest-impact timeout to set first?
requestTimeout on the server. It prevents one slow handler from holding connections until the load balancer gives up.
Should I run HTTPS directly in Node?
Only for local dev or gRPC. Production APIs should terminate TLS at the proxy and run HTTP/1.1 to Node.
How do I test keep-alive alignment?
Run rolling deploys under load (k6 or artillery) and watch for 502 spikes. If they correlate with deploys, lower keepAliveTimeout.
Is plain HTTP ever acceptable?
On private VPC east-west traffic behind mTLS mesh, yes. Never on public internet-facing endpoints.
When should I skip frameworks entirely?
Health sidecars, webhook receivers under 5 endpoints, and internal tools with no auth. Everything else benefits from Express or Fastify conventions.
Related
- HTTP Basics in Node - foundations
- Express Basics - framework layer
- Fastify Basics - performance-oriented framework
- Security Middleware - production hardening
- Framework Selection Checklist - when to upgrade
Stack versions: This page was written for Node.js 24.18.0 (Active LTS), npm 10+, TypeScript 5.6+, Express 5, Fastify 5, and NestJS 11.