Every HTTP request requires a TCP connection. Opening a new connection involves a TCP handshake and, for HTTPS, a TLS handshake — adding tens to hundreds of milliseconds of latency before the first byte of data is transferred. Connection pooling solves this by keeping connections alive and reusing them for subsequent requests, eliminating the handshake overhead entirely. undici provides several dispatcher types with different pooling characteristics. Choosing the right one depends on how many origins you need to reach and how much control you need over the connection count.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/nodejs/undici/llms.txt
Use this file to discover all available pages before exploring further.
Why connection pooling matters
Without pooling, each request would:- Resolve DNS for the hostname
- Open a TCP connection (SYN / SYN-ACK / ACK)
- Complete a TLS handshake (for HTTPS)
- Send the request
- Receive the response
- Close the connection
Choosing the right dispatcher
Client
Single connection, single origin. Use when you need exactly one TCP/TLS connection to a known upstream. Pipelining is disabled by default.
Pool
Multiple connections, single origin. Distributes requests across a configurable number of
Client instances. The connections option controls the pool size (null = unlimited).BalancedPool
Multiple connections, multiple origins. Weighted round-robin across a set of upstreams. Useful for distributing load across known backend servers.
Agent
Automatic pooling, any number of origins. Creates and manages one
Pool per origin automatically. This is the default global dispatcher and the right choice for general-purpose use.When to use each
| Scenario | Recommended dispatcher |
|---|---|
| Talking to one known backend, need precise control | Client |
| High-throughput requests to one origin | Pool with tuned connections |
| Load-balancing across a fixed set of backends | BalancedPool |
| General-purpose HTTP client for multiple origins | Agent (default) |
| Proxying through HTTP/HTTPS proxy | ProxyAgent |
Client: single connection
Client opens one TCP/TLS connection to a single origin. All requests share that one socket. This is the foundation on which Pool and Agent are built.
creating a Client
Client connects lazily — the socket is only opened when the first request is queued.
Pool: multiple connections to one origin
Pool manages a set of Client instances connected to the same upstream. When a request arrives, it picks an available client from the pool. If all clients are busy and the pool has not reached its connection limit, it creates a new Client.
creating a Pool with connection limit
connections is null (the default), the pool grows unbounded. Set an explicit limit to avoid exhausting file descriptors or server connection limits.
Pool stats
inspecting pool stats
BalancedPool: multiple origins
BalancedPool uses a weighted round-robin algorithm to distribute requests across multiple upstream Pool instances. Each upstream gets a weight, and the algorithm adjusts weights based on errors.
BalancedPool across multiple backends
Agent: automatic pooling for multiple origins
Agent is the most flexible dispatcher. It creates a Pool per origin on demand and cleans them up when they become idle. This is the default global dispatcher.
The internal factory function chooses between Client and Pool based on the connections option:
agent factory logic (from lib/dispatcher/agent.js)
creating a custom Agent
Key options
Timeout options
Milliseconds an idle socket remains open before closing. Overridden by server
keep-alive hints. Default: 4 seconds.Maximum
keepAliveTimeout in milliseconds when the server overrides it via keep-alive hints. Default: 10 minutes.Milliseconds subtracted from server keep-alive hints to account for transport latency. Default: 2 seconds.
Milliseconds to wait for complete HTTP headers after sending a request. Default: 300 seconds.
Milliseconds between body data chunks before timing out. Set to
0 to disable. Default: 300 seconds.Milliseconds to wait when establishing a new TCP/TLS connection. Configured via the
connect options object.Pool size options
Maximum number of
Client instances in a Pool. null means unlimited. On Agent, applies to each per-origin pool.Number of concurrent requests per connection. Set to
0 to disable keep-alive. Values greater than 1 enable HTTP pipelining.Milliseconds before a
Client instance is removed from the pool and closed. Useful for forcing connection rotation.Tuning for high-throughput workloads
tuning a Pool for high throughput
TLS session reuse with maxCachedSessions
For HTTPS connections, TLS handshakes add significant overhead. undici caches TLS sessions so subsequent connections can skip the full handshake (TLS session resumption).
The maxCachedSessions option is passed through the connect configuration object:
Maximum number of TLS sessions cached per origin. Set to
0 to disable TLS session caching entirely.configuring TLS session caching
Connection lifecycle
A connection in undici moves through these states:- Idle: connected but no active request. The socket is kept alive up to
keepAliveTimeoutmilliseconds. - Active: a request is in progress. The socket is sending or receiving data.
- Closed: the socket has been destroyed. The pool may open a new connection for subsequent requests.
The body consumption requirement
consuming the body in every code path
| Method | When to use |
|---|---|
body.json() / body.text() / body.arrayBuffer() | You need the response content |
body.dump() | You do not need the content but want to keep the connection |
body.destroy() | You want to close the connection immediately |