Node's HTTP server has built in timeouts against slow senders. headersTimeout limits how long the server waits for complete headers, requestTimeout limits how long it waits for the entire request, and keepAliveTimeout closes idle connections. Check each value, because the defaults are not all strict, and server.timeout is off.
Definitions and documented defaults
| Setting | Documented default | What it limits |
|---|---|---|
| headersTimeout | The smaller of requestTimeout or 60000 ms | Time to receive complete headers |
| requestTimeout | 300000 ms (5 minutes) | Time to receive the entire request |
| keepAliveTimeout | 5000 ms | Idle time between requests on a socket |
| timeout | 0 (none) | Socket inactivity |
| maxHeadersCount | 1000 | Number of incoming headers |
| connectionsCheckingInterval | 30000 ms | How often incomplete requests are checked |
These values are from the Node.js http documentation. On expiry of the header or request timeout, the server responds with status 408 and closes the connection, without calling your request listener. The documentation also says to keep requestTimeout non zero, for example 120 seconds, to protect against denial of service when the server runs without a reverse proxy in front.
Note the history: server.timeout used to be 120 seconds and became 0 in Node 13. The requestTimeout default changed from none to 5 minutes in Node 18. Older runtimes behave differently, so check your version.
Why slow clients are a problem
A connection costs a socket and some memory even when it sends one byte a second. Open enough of them and legitimate users cannot connect. Timeouts bound how long any single connection can hold a slot without finishing its work.
Steps to tighten them
- Put a reverse proxy in front, and set its client header and body timeouts first. See do you need a reverse proxy in front of Node.
- Set headersTimeout and requestTimeout to values that fit your largest legitimate upload on your slowest realistic connection. For a JSON API, 30 to 60 seconds is often plenty.
- Keep headersTimeout at or below requestTimeout.
- Set keepAliveTimeout above your load balancer's idle timeout so Node does not close connections the balancer thinks are alive. Check your balancer's documentation for its value.
- Load test with a slow sender to confirm you get a 408, not a hang.
const http = require('node:http');
const server = http.createServer(app);
server.headersTimeout = 20000;
server.requestTimeout = 60000;
server.keepAliveTimeout = 65000;
server.listen(3000);
Frameworks pass these through. Fastify, for example, exposes requestTimeout and connectionTimeout in its server options, both defaulting to 0, and recommends a non zero requestTimeout when no reverse proxy is present.
What timeouts do not do
They do not limit body size or request rate. Pair them with a body limit (Express, Fastify) and rate limiting. Uploads that legitimately take longer than your timeout need a separate path or a direct to storage upload.
Safeguard's DAST web app scan and dependency scanning cover the application layer, while timeouts belong to your runtime and proxy configuration. A free scan is at gold.safeguard.sh/scan.
Quick check
Is server.timeout the setting that stops slowloris style attacks?
Not on its own. It defaults to 0 and measures socket inactivity. The header and request timeouts target slow header and body delivery.
What status code does a timed out request get?
The documentation says the server responds with 408 and closes the connection, without forwarding the request to your handler.
Sources
Last reviewed: 19 October 2026.