proxy-agent vs global-agent vs hpagent: HTTP Proxy Agents in Node.js (2026)
TL;DR
proxy-agent maps proxy URIs to the correct agent implementation — auto-selects HTTP, HTTPS, SOCKS4/5 agents based on the proxy URL protocol, used by npm, yarn, and many CLI tools. global-agent bootstraps a global HTTP/HTTPS agent that routes all requests through a proxy — set GLOBAL_AGENT_HTTP_PROXY and every http.request uses it automatically. hpagent is the modern HTTP/HTTPS proxy agent — supports keep-alive connections through HTTPS proxies, handles CONNECT tunneling correctly, minimal and focused. In 2026: proxy-agent for multi-protocol proxy support, global-agent for transparent global proxying, hpagent for reliable HTTPS-over-HTTPS proxy connections.
Key Takeaways
- proxy-agent: ~10M weekly downloads — auto-selects agent by proxy URL protocol
- global-agent: ~5M weekly downloads — patches Node.js globals, all requests proxied
- hpagent: ~3M weekly downloads — HTTPS proxy with keep-alive, CONNECT tunneling
- Corporate environments often require HTTP proxies — these libraries make it work
HTTP_PROXY/HTTPS_PROXYenv vars are the standard — libraries read them- Node.js has no built-in proxy support — you need an agent library
The Problem
Node.js HTTP requests don't support proxies natively:
fetch("https://api.example.com")
// → Direct connection (no proxy)
// But behind a corporate firewall:
// → Connection refused / timeout
Corporate networks require:
HTTP_PROXY=http://proxy.corp.com:8080
HTTPS_PROXY=http://proxy.corp.com:8080
NO_PROXY=localhost,127.0.0.1,.internal.com
// Node.js ignores these env vars by default
// You need a proxy agent library
proxy-agent
proxy-agent — smart proxy selection:
Basic usage
import { ProxyAgent } from "proxy-agent"
// Auto-detects proxy from environment variables:
const agent = new ProxyAgent()
// Uses HTTP_PROXY, HTTPS_PROXY, NO_PROXY automatically:
const response = await fetch("https://api.example.com", {
agent, // Routes through proxy if env vars are set
})
// Or specify proxy explicitly:
const agent2 = new ProxyAgent("http://proxy.corp.com:8080")
Multi-protocol support
import { ProxyAgent } from "proxy-agent"
// HTTP proxy:
new ProxyAgent("http://proxy.corp.com:8080")
// HTTPS proxy:
new ProxyAgent("https://secure-proxy.corp.com:443")
// SOCKS5 proxy:
new ProxyAgent("socks5://socks-proxy.corp.com:1080")
// SOCKS4 proxy:
new ProxyAgent("socks4://socks-proxy.corp.com:1080")
// PAC file (Proxy Auto-Config):
new ProxyAgent("pac+https://corp.com/proxy.pac")
// Auto-selects the right agent implementation based on protocol
With HTTP clients
import { ProxyAgent } from "proxy-agent"
import https from "node:https"
const agent = new ProxyAgent()
// With node:https:
https.get("https://api.example.com", { agent }, (res) => {
// Response through proxy
})
// With fetch (Node.js 18+):
const response = await fetch("https://api.example.com", {
dispatcher: agent, // undici dispatcher
})
// With got:
import got from "got"
const data = await got("https://api.example.com", {
agent: { https: agent },
}).json()
NO_PROXY support
import { ProxyAgent } from "proxy-agent"
// Respects NO_PROXY environment variable:
// NO_PROXY=localhost,127.0.0.1,.internal.com,*.corp.net
const agent = new ProxyAgent()
// These skip the proxy:
fetch("http://localhost:3000", { agent }) // Direct
fetch("https://api.internal.com", { agent }) // Direct
fetch("https://service.corp.net", { agent }) // Direct
// These use the proxy:
fetch("https://api.github.com", { agent }) // Proxied
fetch("https://registry.npmjs.org", { agent }) // Proxied
global-agent
global-agent — transparent global proxy:
Bootstrap
import { bootstrap } from "global-agent"
// Patches Node.js HTTP/HTTPS globals:
bootstrap()
// Now ALL http/https requests use the proxy:
// Reads GLOBAL_AGENT_HTTP_PROXY or HTTP_PROXY
// Every request is now proxied — no agent parameter needed:
const response = await fetch("https://api.example.com")
// → Automatically routes through proxy
Environment variables
# Set proxy via environment variables:
export GLOBAL_AGENT_HTTP_PROXY=http://proxy.corp.com:8080
export GLOBAL_AGENT_HTTPS_PROXY=http://proxy.corp.com:8080
export GLOBAL_AGENT_NO_PROXY=localhost,127.0.0.1
# Or use standard HTTP_PROXY (global-agent reads both):
export HTTP_PROXY=http://proxy.corp.com:8080
export HTTPS_PROXY=http://proxy.corp.com:8080
export NO_PROXY=localhost,127.0.0.1
# Run your app:
node app.js
# All HTTP/HTTPS requests now use the proxy
Programmatic configuration
import { bootstrap } from "global-agent"
bootstrap()
// Configure at runtime:
global.GLOBAL_AGENT.HTTP_PROXY = "http://proxy.corp.com:8080"
global.GLOBAL_AGENT.HTTPS_PROXY = "http://proxy.corp.com:8080"
global.GLOBAL_AGENT.NO_PROXY = "localhost,127.0.0.1"
// Disable for specific requests by passing agent: false
// (implementation depends on the HTTP client)
Use case: CLI tools
// Perfect for CLI tools that need corporate proxy support:
#!/usr/bin/env node
import { bootstrap } from "global-agent"
// Bootstrap before any HTTP requests:
bootstrap()
// Now all npm registry requests, API calls, etc. use proxy:
import { fetchPackageInfo } from "./api.js"
const info = await fetchPackageInfo("react")
hpagent
hpagent — modern HTTPS proxy agent:
Basic usage
import { HttpsProxyAgent } from "hpagent"
const agent = new HttpsProxyAgent({
proxy: "http://proxy.corp.com:8080",
keepAlive: true, // Reuse proxy connections
keepAliveMsecs: 1000,
maxSockets: 256,
maxFreeSockets: 256,
})
// Use with https:
import https from "node:https"
https.get("https://api.example.com", { agent }, (res) => {
// Response tunneled through proxy
})
HTTP and HTTPS agents
import { HttpProxyAgent, HttpsProxyAgent } from "hpagent"
// For HTTP targets (http://...):
const httpAgent = new HttpProxyAgent({
proxy: "http://proxy.corp.com:8080",
keepAlive: true,
})
// For HTTPS targets (https://...):
const httpsAgent = new HttpsProxyAgent({
proxy: "http://proxy.corp.com:8080",
keepAlive: true,
})
// With got:
import got from "got"
const data = await got("https://api.example.com", {
agent: {
http: httpAgent,
https: httpsAgent,
},
}).json()
Why hpagent over alternatives
hpagent advantages:
✅ Correct HTTPS-over-HTTPS (CONNECT tunneling)
✅ Keep-alive through proxy connections
✅ Compatible with Node.js http.Agent API
✅ Minimal — focused on HTTP/HTTPS proxies
✅ Used by Elastic (elasticsearch-js)
vs proxy-agent:
❌ No SOCKS support
❌ No PAC file support
❌ No auto-detection from env vars
✅ Simpler, more focused
✅ Better keep-alive handling
vs global-agent:
❌ Not transparent — must pass agent explicitly
✅ More control per-request
✅ No global monkey-patching
Feature Comparison
| Feature | proxy-agent | global-agent | hpagent |
|---|---|---|---|
| HTTP proxy | ✅ | ✅ | ✅ |
| HTTPS proxy | ✅ | ✅ | ✅ |
| SOCKS4/5 | ✅ | ❌ | ❌ |
| PAC files | ✅ | ❌ | ❌ |
| Auto env vars | ✅ | ✅ | ❌ (manual) |
| Global patching | ❌ | ✅ | ❌ |
| Keep-alive | ✅ | ✅ | ✅ (better) |
| NO_PROXY | ✅ | ✅ | ❌ (manual) |
| Per-request | ✅ | ❌ (global) | ✅ |
| Dependencies | Many (agents) | Few | 0 |
| Weekly downloads | ~10M | ~5M | ~3M |
When to Use Each
Use proxy-agent if:
- Need multi-protocol proxy support (HTTP, HTTPS, SOCKS, PAC)
- Building a CLI tool that should work behind any proxy type
- Want automatic environment variable detection
- npm/yarn use this — battle-tested in package managers
Use global-agent if:
- Want transparent proxying without changing every HTTP call
- Building an app where ALL requests should go through a proxy
- Corporate environment — bootstrap once, everything works
- Don't want to pass agent to every HTTP client
Use hpagent if:
- Need reliable keep-alive connections through HTTPS proxies
- Want explicit per-request proxy control (not global)
- Using Elasticsearch, Fastify, or similar clients that accept agents
- Only need HTTP/HTTPS proxy (no SOCKS/PAC)
Methodology
Download data from npm registry (weekly average, February 2026). Feature comparison based on proxy-agent v6.x, global-agent v3.x, and hpagent v1.x.