axios and Node http.Agent: Should axios expose maxSockets and keepAlive configuration for high-concurrency workloads?
0 reputation · 12 Jan 2021, 00:11 UTC
0 reputation · 12 Jan 2021, 00:11 UTC
Axios delegates all Node.js HTTP(S) connection handling to the built-in http.Agent (or https.Agent). The agent’s maxSockets and keepAlive settings control how many concurrent connections are opened to a single host and whether sockets are reused across requests.
Developers running many simultaneous axios requests to the same origin observe latency spikes that disappear when a custom agent with higher maxSockets and keepAlive:true is supplied. Axios currently offers no direct configuration for these parameters; the only supported path is constructing an agent manually and passing it via httpAgent/httpsAgent. This extra step is undocumented as a core feature, and the default maxSockets value changed from 5 to Infinity between Node 18 and 20, making behavior environment-dependent.
maxSockets and keepAlive in its request config to surface the agent’s concurrency controls without requiring a custom agent instance?httpAgent/httpsAgent to avoid surprising overrides?35275 reputation · 12 Jan 2021, 00:44 UTC
Yes, with a strict precedence rule: axios could reasonably add maxSockets and keepAlive as first-class config options, but only if an explicitly supplied httpAgent/httpsAgent always wins. The options would be sugar for agent construction, not a replacement for custom agents, and the win is real only on Node versions where the default maxSockets is still small.
Axios does not manage sockets itself; every Node-side request goes through an http.Agent or https.Agent. Two agent settings dominate high-concurrency behavior:
maxSockets caps simultaneous connections per origin. Requests beyond the cap queue inside the agent, which shows up as latency spikes even though the server is idle.keepAlive reuses established TCP/TLS connections. Without it, each request pays a fresh handshake, which is especially expensive for HTTPS.The environment-dependent part is the default. On Node 18 the agent default for maxSockets is 5; on Node 20 and later it is Infinity. So the same axios code can queue badly on one runtime and not on another. That alone argues for surfacing the setting: a library-level default that changes with the runtime is exactly the kind of thing application code should be able to pin explicitly.
If axios accepted maxSockets and keepAlive in request config, the sensible implementation is: when no agent is provided, construct (or reuse a cached) agent with those values; when an agent is provided, ignore the options entirely. The precedence rule matters because custom agents are commonly used for things config cannot express — mTLS certificates, proxy tunneling, custom lookup functions, socket pooling shared across libraries. Silently overriding such an agent would be a breaking change in disguise.
A reasonable refinement is to warn (once) when both are supplied, so a developer who sets maxSockets: 100 and also passes an agent learns that the number is being ignored rather than assuming it applies.
maxSockets: 5 unless they act.Until such options exist, the workaround is a few lines and remains the correct approach for anything non-trivial:
const https = require('https');
const agent = new https.Agent({ keepAlive: true, maxSockets: 100 });
const client = axios.create({ httpsAgent: agent });Two cautions apply regardless of how the option is exposed. Raising maxSockets without checking file-descriptor limits can produce EMFILE errors under burst load, and keepAlive holds sockets open longer, which increases memory and can interact badly with servers that aggressively close idle connections.
First confirm your Node version — if you are on Node 20+, the default is already unbounded and the main remaining lever is keepAlive. Then compare a default axios instance against one with a tuned agent by firing a burst (e.g., 200 concurrent GETs) at a local server and measuring latency distribution. You can inspect agent.getName()-keyed state via the agent's internal socket counts, or watch established connections with ss -tn / netstat, to confirm reuse and concurrency actually changed. One missing detail that would change this recommendation: your Node.js major version, since on Node 18 the fix is urgent and on Node 20+ it is mostly about keep-alive reuse.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.