Undici Proxy Setup
Undici is Node.js's built-in HTTP client (powering the global `fetch` in Node 18+) and the fastest HTTP/1.1 client available for Node.js. Its dispatcher architecture makes proxy integration clean and composable — you create a ProxyAgent once and pass it as the dispatcher for any request. Undici handles the CONNECT tunnel, keep-alive, and connection pooling through the proxy automatically.
Basic Configuration
import { request, ProxyAgent } from 'undici';
const proxyUrl = \`http://\${process.env.PROXY_USER}:\${process.env.PROXY_PASS}@gate.hexproxies.com:8080\`;
const proxyAgent = new ProxyAgent(proxyUrl);
const { statusCode, body } = await request('https://httpbin.org/ip', {
dispatcher: proxyAgent,
headers: {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)',
},
});
const data = await body.json();
console.log(statusCode, data);Using with Node.js Global Fetch
Node 18+ includes a global `fetch` powered by Undici. You can route it through a proxy by setting the global dispatcher:
import { setGlobalDispatcher, ProxyAgent } from 'undici';
const proxyAgent = new ProxyAgent({
uri: \`http://\${process.env.PROXY_USER}:\${process.env.PROXY_PASS}@gate.hexproxies.com:8080\`,
keepAliveTimeout: 30000,
keepAliveMaxTimeout: 60000,
connections: 20,
});
setGlobalDispatcher(proxyAgent);
// All global fetch calls now route through the proxy
const res = await fetch('https://example.com');
console.log(await res.text());Connection Pooling and Performance
Undici's ProxyAgent maintains a connection pool to the proxy gateway. Configure the pool size to match your proxy plan's concurrency limit:
const proxyAgent = new ProxyAgent({
uri: proxyUrl,
connections: 50, // max concurrent connections to proxy
pipelining: 1, // requests per connection (1 for proxy compatibility)
keepAliveTimeout: 10000, // ms to keep idle connections alive
});Common Pitfalls
The most common mistake is creating a new ProxyAgent for every request. Each agent allocates a connection pool — creating hundreds of agents wastes memory and prevents connection reuse. Always create one agent and share it across requests.
Another subtle issue: Undici's default request timeout is 30 seconds. Residential proxies add 200-500ms latency per request. For large pages or slow targets, increase the timeout:
const { body } = await request(url, {
dispatcher: proxyAgent,
headersTimeout: 15000,
bodyTimeout: 30000,
});Retry Logic for Proxy Errors
Undici does not retry failed requests automatically. Implement retry logic with exponential backoff for proxy connection resets and 429 responses. Distinguish between proxy-layer failures (retry immediately) and target-layer blocks (backoff before retrying).
IP Rotation
For per-request IP rotation, generate a unique session ID and embed it in the proxy username. Create a new ProxyAgent per session group, or use the Hex Proxies gateway's automatic rotation mode where each new connection gets a fresh IP.