<!-- PkgPulse AI-readable guide source -->
<!-- Canonical: https://www.pkgpulse.com/guides/proxy-agent-vs-global-agent-vs-hpagent-http-proxy-2026 -->
<!-- Raw Markdown: https://www.pkgpulse.com/guides/proxy-agent-vs-global-agent-vs-hpagent-http-proxy-2026/raw.md -->
<!-- Source path: content/guides/proxy-agent-vs-global-agent-vs-hpagent-http-proxy-2026.mdx -->

---
og_image: "/images/guides/proxy-agent-vs-global-agent-vs-hpagent-http-proxy-2026.webp"
title: "proxy-agent vs global-agent vs hpagent 2026"
description: "proxy-agent, global-agent, and hpagent for Node.js HTTP proxy routing in 2026. SOCKS5, environment variables, and global vs per-client proxy configuration."
date: "2026-03-09"
tier: 2
authors: ["team"]
tags: ["nodejs", "typescript", "http", "proxy", "developer-tools"]
---

## 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](https://github.com/TooTallNate/proxy-agents) — smart proxy selection:

### Basic usage

```typescript
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

```typescript
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

```typescript
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

```typescript
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](https://github.com/gajus/global-agent) — transparent global proxy:

### Bootstrap

```typescript
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

```bash
# 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

```typescript
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

```typescript
// 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](https://github.com/delvedor/hpagent) — modern HTTPS proxy agent:

### Basic usage

```typescript
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

```typescript
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.

## 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:

```typescript
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 →](https://www.pkgpulse.com)*

*See also: [h3 vs polka vs koa 2026](/guides/h3-vs-polka-vs-koa-lightweight-http-frameworks-nodejs-2026) and [http-proxy-middleware vs node-http-proxy vs fastify-http-proxy: Reverse Proxy in Node.js 2026](/guides/http-proxy-middleware-vs-node-http-proxy-vs-fastify-2026), [better-sqlite3 vs libsql vs sql.js](/guides/better-sqlite3-vs-libsql-vs-sql-js-sqlite-nodejs-2026).*
