Axios Connection Timeout vs Socket Timeout Guide
Managing network timeouts properly is essential for building resilient applications, preventing hung processes, and handling slow or unresponsive upstream services. In network communication, a connection timeout and a socket (read) timeout represent two distinct phases of an HTTP request. This guide explains the differences between connection timeouts and socket timeouts and demonstrates how to configure both when using Axios in Node.js.
Understanding Connection Timeout vs. Socket Timeout
Before configuring Axios, it is important to distinguish how these two timeouts function:
- Connection Timeout: The maximum time allowed to establish the initial TCP handshake (and TLS negotiation for HTTPS) with the destination server. If the server does not respond within this window, the connection attempt is aborted.
- Socket Timeout (Read/Inactivity Timeout): The maximum period of inactivity between two consecutive data packets after the connection has been established. If the connection is established but the server pauses or stops sending data mid-stream, the socket timeout triggers.
By default, the standard timeout property in Axios
(axios.create({ timeout: 5000 })) applies to the
entire request lifecycle—from the initial request
dispatch until the response data is fully received. It does not natively
separate connection establishment from socket read inactivity.
Configuring Socket Timeout with HTTP/HTTPS Agents
In Node.js, Axios relies on the native http and
https modules. You can configure socket-level timeouts by
passing custom http.Agent and https.Agent
instances to Axios.
const axios = require('axios');
const http = require('http');
const https = require('https');
// Create custom agents with socket inactivity timeouts
const httpAgent = new http.Agent({
keepAlive: true,
timeout: 10000 // Socket timeout in milliseconds (10 seconds)
});
const httpsAgent = new https.Agent({
keepAlive: true,
timeout: 10000 // Socket timeout in milliseconds (10 seconds)
});
const client = axios.create({
httpAgent,
httpsAgent
});When configured this way, the underlying TCP socket will emit a
timeout event if no data is transmitted across the socket
for 10 seconds.
Configuring a Dedicated Connection Timeout
Because Node.js and Axios do not provide a dedicated
connectionTimeout configuration property out of the box,
you can implement one by intercepting the request's socket creation and
applying a timer that clears once the socket connects.
Using Request Hooks and Socket Events
You can listen for the socket event on the underlying
http.ClientRequest to enforce a strict connection
deadline:
const axios = require('axios');
const http = require('http');
const https = require('https');
async function makeRequestWithCustomTimeouts(url, options = {}) {
const {
connectionTimeout = 3000, // 3 seconds to connect
socketTimeout = 5000, // 5 seconds between data packets
...axiosConfig
} = options;
const httpAgent = new http.Agent({ keepAlive: true, timeout: socketTimeout });
const httpsAgent = new https.Agent({ keepAlive: true, timeout: socketTimeout });
const instance = axios.create({
httpAgent,
httpsAgent,
...axiosConfig
});
// Intercept request to monitor socket connection state
instance.interceptors.request.use((config) => {
config.transformRequest = [
(data, headers) => {
return data;
}
];
return config;
});
const response = await instance.get(url, {
transport: {
request: (options, callback) => {
const req = (options.protocol === 'https:' ? https : http).request(options, callback);
let connectionTimer = setTimeout(() => {
req.destroy(new Error(`Connection timeout: Exceeded ${connectionTimeout}ms during connection phase`));
}, connectionTimeout);
req.on('socket', (socket) => {
// Check if socket is already connected (e.g., reused via keepAlive)
if (socket.connecting) {
socket.once('connect', () => {
clearTimeout(connectionTimer);
});
socket.once('secureConnect', () => {
clearTimeout(connectionTimer);
});
} else {
clearTimeout(connectionTimer);
}
// Handle socket inactivity
socket.setTimeout(socketTimeout, () => {
req.destroy(new Error(`Socket timeout: Inactivity exceeded ${socketTimeout}ms`));
});
});
return req;
}
}
});
return response;
}Using AbortController for Connection Timeouts
For a lightweight implementation without modifying underlying
transport layers, you can use AbortController to handle the
total connection phase independently:
const axios = require('axios');
const http = require('http');
const https = require('https');
async function fetchWithTimeouts(url) {
const controller = new AbortController();
const connectionTimeoutMs = 3000;
const socketTimeoutMs = 7000;
const httpAgent = new http.Agent({ timeout: socketTimeoutMs });
const httpsAgent = new https.Agent({ timeout: socketTimeoutMs });
const timeoutId = setTimeout(() => {
controller.abort(new Error(`Connection timed out after ${connectionTimeoutMs}ms`));
}, connectionTimeoutMs);
try {
const response = await axios.get(url, {
signal: controller.signal,
httpAgent,
httpsAgent,
onDownloadProgress: () => {
// Clear the connection timeout once data starts streaming
clearTimeout(timeoutId);
}
});
clearTimeout(timeoutId);
return response.data;
} catch (error) {
clearTimeout(timeoutId);
throw error;
}
}Summary of Configuration Methods
| Timeout Type | Mechanism in Node.js / Axios | Target Failure Mode |
|---|---|---|
| Total Request Timeout | Axios timeout option |
Entire request/response takes too long. |
| Socket Timeout | http.Agent({ timeout }) or
socket.setTimeout() |
Data flow stops or hangs after connecting. |
| Connection Timeout | Socket connection listeners or
AbortController |
Server is unreachable, dropping SYN packets, or failing TLS negotiation. |