Skip to main content

Guide

proxy-agent vs global-agent vs hpagent 2026

proxy-agent, global-agent, and hpagent for Node.js HTTP proxy routing in 2026. SOCKS5, environment variables, and global vs per-client proxy configuration.

·PkgPulse Team·
0

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_PROXY env 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

Featureproxy-agentglobal-agenthpagent
HTTP proxy
HTTPS proxy
SOCKS4/5
PAC files
Auto env vars❌ (manual)
Global patching
Keep-alive✅ (better)
NO_PROXY❌ (manual)
Per-request❌ (global)
DependenciesMany (agents)Few0
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.

Proxy Authentication and TLS Certificate Handling

Corporate proxies often require authentication, and HTTPS proxies introduce TLS complexity that each library handles differently.

HTTP Basic authentication is supported by all three libraries via the proxy URL: http://username:password@proxy.corp.com:8080. Credentials in the URL are Base64-encoded into the Proxy-Authorization header automatically. For more complex authentication schemes (NTLM, Kerberos), none of the three libraries provide built-in support — those protocols require enterprise-grade middleware or dedicated packages like ntlm-auth.

TLS certificate validation in corporate environments is a common pain point. Many corporate proxies perform SSL inspection using a self-signed or internally-signed root certificate. Node.js will reject these connections with UNABLE_TO_VERIFY_LEAF_SIGNATURE or SELF_SIGNED_CERT_IN_CHAIN errors. The solution is to add the corporate root certificate to the trusted CA bundle:

import https from "node:https"
import fs from "node:fs"

// Add corporate root CA to trusted certificates:
const ca = fs.readFileSync("/path/to/corporate-root-ca.pem")
const agent = new https.Agent({ ca })

// Then use with hpagent:
import { HttpsProxyAgent } from "hpagent"
const proxyAgent = new HttpsProxyAgent({
  proxy: "http://proxy.corp.com:8080",
  ca,  // hpagent accepts tls.SecureContextOptions
})

hpagent exposes the full Node.js tls.connect options through its constructor, making it straightforward to pass custom CA certificates, client certificates, or disable certificate verification (rejectUnauthorized: false — only appropriate for development environments). proxy-agent delegates certificate handling to the underlying agent implementations, while global-agent patches the global defaults.


Integration with Modern HTTP Clients

The proxy agent ecosystem evolved alongside Node.js's HTTP stack, and 2026's preferred HTTP clients have varying levels of support for the agent pattern.

Node.js native fetch (available since Node.js 21 without a flag) is built on undici and uses a different interface than the traditional http.Agent. It accepts a dispatcher option instead of agent. proxy-agent returns an undici-compatible ProxyAgent in its latest versions, making it compatible with native fetch. hpagent does not yet provide undici dispatchers, so using it with native fetch requires wrapping with a compatibility shim or using the older node:https API.

got (the popular HTTP request library) has first-class support for all three proxy agents via its agent option, which accepts separate HTTP and HTTPS agents. got's retry logic and timeout handling work correctly through proxied connections with all three libraries.

axios accepts an httpAgent and httpsAgent configuration option at the instance level. hpagent is commonly recommended with axios due to its correct keep-alive behavior — axios itself uses persistent connections, and hpagent ensures those connections are properly tunneled through the proxy.

undici (Node.js's modern HTTP client) has a native ProxyAgent class (undici.ProxyAgent) that is separate from all three libraries discussed here. For new Node.js projects not targeting legacy compatibility, the built-in undici.ProxyAgent is worth evaluating before adding a third-party dependency. It lacks SOCKS support but handles HTTP/HTTPS proxy correctly with keep-alive.


Proxy Configuration in CI and Container Environments

Container-based CI environments (Docker, Kubernetes) have different proxy configuration challenges than local development. Environment variables must be explicitly passed into containers, and network policies may require proxy use for outbound internet access while exempting internal cluster traffic.

The standard approach is to set HTTP_PROXY, HTTPS_PROXY, and NO_PROXY environment variables at the container or pod level. Both proxy-agent and global-agent read these variables automatically. hpagent requires explicit configuration, making it less suitable for environments where the proxy URL is only known at runtime via environment injection.

Docker Compose users can set proxy variables in the environment section of their service definition. Kubernetes users configure them in the container env spec or via envFrom from a ConfigMap. The NO_PROXY variable is critical for preventing proxy use on internal services — a common mistake is forgetting to exclude cluster-internal DNS names (.cluster.local, .svc, 10.0.0.0/8), causing internal service calls to fail when they route through an external proxy.

For Lambda functions and other serverless environments behind a corporate VPN, global-agent is particularly useful because bootstrapping once at the top of the handler file transparently proxies all SDK calls (AWS SDK, HTTP requests) without modifying the SDK configuration itself.

Summary: When to Use Each

The three libraries serve overlapping but distinct use cases. Choose based on your HTTP client and runtime environment:

proxy-agent — the most versatile choice for node:http and node:https based clients. If you use axios, the built-in https.request, or libraries that accept an agent option, proxy-agent gives you SOCKS4, SOCKS5, HTTP, and HTTPS proxy support from a single package. The auto-detection from HTTP_PROXY/HTTPS_PROXY environment variables makes it drop-in for most corporate network environments.

global-agent — the right choice when you cannot modify the HTTP client's configuration. If you are using the AWS SDK, node-fetch, or any client that does not expose an agent option, global-agent patches the Node.js internals globally, which means all outbound HTTP/HTTPS requests are routed through the proxy without code changes. Use with caution in shared environments or libraries.

hpagent — a focused solution for got, undici, or any client that supports a dispatcher option. Its main advantage over the others is transparent proxy authentication and HTTPS-over-HTTPS tunneling without patching Node.js globals. If your HTTP clients already use the undici dispatcher model, hpagent is the cleanest integration path.

A practical concern in corporate environments: many enterprise proxies perform TLS inspection, where the proxy terminates the HTTPS connection, inspects the payload, and re-establishes a connection to the destination using a corporate root CA certificate. All three libraries handle standard CONNECT-based HTTPS proxies, but TLS-inspecting proxies require configuring Node.js to trust the corporate root CA via NODE_EXTRA_CA_CERTS or by importing the certificate into the custom agent. This is an operational concern rather than a library feature — but it's the source of many "works on my laptop, fails in CI" proxy bugs.

Compare HTTP networking and developer tooling on PkgPulse →

See also: h3 vs polka vs koa 2026 and http-proxy-middleware vs node-http-proxy vs fastify-http-proxy: Reverse Proxy in Node.js 2026, better-sqlite3 vs libsql vs sql.js.

The 2026 JavaScript Stack Cheatsheet

One PDF: the best package for every category (ORMs, bundlers, auth, testing, state management). Used by 500+ devs. Free, updated monthly.