JavaScript HTTP client guide

Node.js Proxy Guide: Fetch, Axios, Undici and Environment Variables

Configure private proxies in modern Node.js with built-in environment support, Undici dispatchers, Axios, secure credentials, bypass rules and error handling.

Node.js HTTP proxy configuration choices
Choose one proxy mechanism for each Node.js code path, secure its configuration and verify the actual route.

Short answer: how to use proxies in Node.js

Modern Node.js releases can use HTTP_PROXY, HTTPS_PROXY and NO_PROXY through built-in proxy support when explicitly enabled. Undici also provides ProxyAgent and EnvHttpProxyAgent for fetch-style requests. Axios has its own request configuration. Choose one routing mechanism for a code path, keep credentials in secrets, and verify the final exit.

Proxy behavior is version-sensitive. The current Node.js HTTP documentation marks built-in proxy support as active development and documents the versions where it was added. Check the runtime used by local development, CI and production before copying an example.

Do not stack proxy mechanisms blindly. Environment variables, a global dispatcher and a library-specific agent can conflict. Pick one owner for routing and document bypass rules.

Built-in Node.js proxy support

For the built-in HTTP stack, Node documents NODE_USE_ENV_PROXY=1 and --use-env-proxy from Node 24.5.0 and the 22.21.0 backport. Check node --version in the process that runs the application before using this startup example; an older 22.x or 24.x patch release may not provide the same support. The feature is still marked active development in the official command-line reference, reviewed 13 October 2026.

# Linux or macOS: each startup command is one line
NODE_USE_ENV_PROXY=1 HTTPS_PROXY="http://user:pass@proxy.example:8080" NO_PROXY="localhost,127.0.0.1,.internal.example" node app.mjs

# Or use the command-line flag
HTTPS_PROXY="http://proxy.example:8080" node --use-env-proxy app.mjs
const response = await fetch('https://api.ipify.org?format=json', {
  signal: AbortSignal.timeout(30_000)
});

if (!response.ok) {
  throw new Error(`IP check failed with ${response.status}`);
}

console.log(await response.json());

Node documents lower- and uppercase proxy variables and their precedence. Its native http/https agents support exact hosts, suffixes, wildcards, IPs, IPv4 ranges and host-port pairs in NO_PROXY. Built-in fetch and Undici EnvHttpProxyAgent use a different matcher; do not assume native-agent IP-range rules apply to them. Test bypass rules in the client and version you deploy: an overly broad entry can silently send sensitive traffic directly.

Never store an authenticated proxy URL in a checked-in .env file. The official environment variables guide explains process.env and dotenv syntax, but secret storage and deployment permissions remain your responsibility.

Use Undici EnvHttpProxyAgent

Undici’s EnvHttpProxyAgent reads HTTP, HTTPS and NO_PROXY values and can be supplied as a local dispatcher or installed globally. A local dispatcher makes the routing decision explicit for one request group.

import {
  EnvHttpProxyAgent,
  fetch
} from 'undici';

const dispatcher = new EnvHttpProxyAgent();

try {
  const response = await fetch(
    'https://api.ipify.org?format=json',
    {
      dispatcher,
      signal: AbortSignal.timeout(30_000)
    }
  );

  if (!response.ok) {
    throw new Error(`Unexpected status ${response.status}`);
  }

  console.log(await response.json());
} finally {
  await dispatcher.close();
}

The official EnvHttpProxyAgent documentation describes variable precedence, bypass matching and local or global dispatcher use. Close a locally created dispatcher during application shutdown so connections do not remain open unexpectedly.

Node.js HTTP proxy environment configuration
Make HTTP_PROXY, HTTPS_PROXY and NO_PROXY explicit, secure and testable across environments.

Configure an HTTP proxy in Axios

Axios exposes a request-level proxy object for HTTP proxy routing in Node.js. This is useful when one client instance owns the policy. Do not also install a conflicting global agent unless you understand which option wins.

import axios from 'axios';

const client = axios.create({
  timeout: 30_000,
  proxy: {
    protocol: 'http',
    host: process.env.PROXY_HOST,
    port: Number(process.env.PROXY_PORT),
    auth: process.env.PROXY_USERNAME
      ? {
          username: process.env.PROXY_USERNAME,
          password: process.env.PROXY_PASSWORD || ''
        }
      : undefined
  }
});

try {
  const { data, status } = await client.get('https://api.ipify.org?format=json');
  console.log(status, data);
} catch (error) {
  const status = Number.isInteger(error.response?.status)
    ? error.response.status
    : 'unavailable';
  console.error('Proxy request failed; HTTP status:', status);
  process.exitCode = 1;
}

The official Axios request configuration documents proxy and environment behavior. SOCKS usually requires a compatible agent rather than the HTTP proxy object. Confirm the library and agent documentation instead of changing the protocol label in a URL and assuming support.

Runtime checks: 14 October 2026

We checked these request examples on Windows with Node.js 24.17.0, its bundled Undici 7.28.0, imported Undici 7.30.0 and Axios 1.20.0. Controlled local HTTP and HTTPS services and an authenticated HTTP proxy fixture recorded the request route. These checks used synthetic credentials and a synthetic IP response; they do not measure a BuyProxies exit or pool.

Client Request controls passed Routing observed
Built-in fetch 12 Environment and flag opt-in used the proxy; no opt-in connected directly. An exact NO_PROXY host bypassed it. An IPv4 dash range did not bypass it, and HTTPS used HTTP_PROXY when HTTPS_PROXY was absent.
Undici EnvHttpProxyAgent 10 An exact NO_PROXY host bypassed the proxy. The same IPv4 dash range did not bypass it; HTTPS fell back to HTTP_PROXY.
Axios with the explicit proxy object above 8 Both target schemes used the configured HTTP proxy. HTTPS used CONNECT. The explicit proxy object still used the proxy when NO_PROXY named the destination.

Each client was checked with HTTP and HTTPS success, incorrect proxy authentication, an untrusted target certificate, target status 403, a same-fixture redirect and the unchanged 30-second timeout. Certificate verification stayed enabled; successful HTTPS checks added an ephemeral fixture CA to the child process trust. The corrected Axios example printed no synthetic authentication data in any of its eight controls.

Two separate native-agent diagnostics confirmed that Node’s native HTTP agent matched the IPv4 dash range, while its native HTTPS agent connected directly when only HTTP_PROXY was set. These diagnostics are distinct from the fetch examples. Compare the versioned Node HTTP reference and Undici environment-agent documentation when choosing a bypass rule.

The POSIX startup commands were checked through equivalent process environment and flag settings on Windows; their Linux/macOS shell syntax was not executed. HTTPS proxies, SOCKS, other Node or package versions, real external exits and production throughput were not tested.

Design NO_PROXY rules carefully

NO_PROXY is a routing policy, not a convenience string. Add local development hosts, private services or destinations that must connect directly only when that behavior is intentional. Test exact hosts, subdomains and ports separately.

Pattern Typical meaning Risk to check
localhost Bypass local hostname Does not always imply every loopback IP form
127.0.0.1 Bypass IPv4 loopback Add IPv6 loopback if the application uses it
.internal.example Bypass matching domain suffix Confirm exact implementation semantics
example.com:8443 Bypass one host and port Other ports may still use the proxy
* Bypass everything Effectively disables proxy routing

Log whether a request used the named routing policy, but do not log the full authenticated proxy URL. A safe record includes a masked proxy ID, destination hostname, bypass decision, duration, status and error category.

Handle Node.js proxy errors without losing evidence

  • Use a total timeout or AbortSignal for every external request.
  • Preserve error code, cause and proxy stage before wrapping the error.
  • Distinguish proxy 407 from target 401 or 403.
  • Do not retry DNS, TLS and authentication failures identically.
  • Retry only safe operations with bounded backoff and jitter.
  • Respect 429 and Retry-After from the target service.
  • Close custom agents and dispatchers during shutdown.

A connection timeout can come from DNS, proxy reachability, the CONNECT tunnel or target. Test the proxy separately with the proxy tester, then reproduce one request with the cURL proxy guide. The error code guide helps classify the result.

Node.js proxy request failure layers
Keep DNS, connection, proxy authentication, TLS and target HTTP evidence separate.

Proxy pools and request assignment

A Node.js service should acquire proxies from one pool component rather than choosing a random array entry in every function. The pool owns health state, location, concurrency, quarantine and credentials. A request receives a lease, uses the proxy for the required session, records the result and releases the lease.

For a stateful sequence, reuse the same dispatcher or proxy assignment. For independent read requests, a new job may receive a different healthy proxy. Connection reuse can keep traffic on an existing route, so rotation must happen at a boundary the HTTP client actually respects.

Use proxy pool management for health and quarantine, and proxy pool sizing for concurrency and reserve. Do not use a larger pool to evade a destination’s rate limit.

For deployment, the Docker proxy guide separates container proxy settings from application configuration. If the same request is part of a visual automation, follow the n8n HTTP Request proxy walkthrough.

Credential and logging checklist

  • Store proxy credentials in a secret manager or protected runtime environment.
  • Encode URL username and password safely when constructing a URL.
  • Redact Proxy-Authorization and authenticated URLs from errors.
  • Restrict secret access to the service and environment that need it.
  • Rotate credentials when staff, runners or deployments change.
  • Do not return proxy configuration to browser clients.
  • Use the authentication guide to choose password or IP allowlisting.

For API-focused workflows, continue with Proxies for API Testing. For browser execution, use the dedicated Playwright or Puppeteer guides rather than forcing a server-side HTTP agent into a browser process.

Choose the Node.js proxy method by runtime and HTTP client

There is no single proxy switch that automatically controls every Node.js networking library. Start with the runtime version and the client that actually sends the request. Newer Node releases can apply environment proxy settings to the built-in HTTP stack when the feature is enabled, while Undici offers an environment-aware dispatcher. Axios has its own request configuration, and a third-party SDK may wrap another transport entirely. Confirm the library path instead of assuming that an exported variable was consumed.

For a new service, centralize outbound HTTP creation in one module. That module can select the dispatcher or agent, apply timeouts, enforce redaction and expose a small health-check function. Business code then asks for an approved client rather than creating ad hoc Axios or fetch instances. This prevents one endpoint from silently bypassing the proxy after a dependency upgrade.

Verify behavior with a small compatibility test

Run the same three checks in development and deployment: an external IP request, an HTTPS request to a representative API and a request to a host covered by NO_PROXY. The first should show the proxy exit, the second confirms CONNECT and TLS behavior, and the third proves that exclusions work. Record the Node version and package lock revision with the result because proxy semantics can change across runtime and client versions.

Reuse connections without mixing proxy identities

Connection pooling improves performance, but the pool belongs to a route. Do not reuse one agent indiscriminately after changing proxy credentials or session identifiers. Maintain a bounded agent per proxy assignment, close idle agents and cap concurrent sockets. For scraping or regional API checks, keep one logical identity for a complete job and rotate between jobs, not between dependent requests.

Build useful error categories

Normalize low-level errors into a small operational vocabulary: DNS resolution, proxy connection, proxy authentication, tunnel establishment, TLS, upstream timeout and target HTTP response. Preserve the original error as structured metadata while keeping secrets out of logs. That distinction matters because retrying a 407 with the same credentials is wasteful, while retrying a transient connection reset on a different verified proxy may be reasonable.

When migrating an existing codebase, change one HTTP client at a time and compare direct and proxied integration tests. Keep a rollback switch, document the supported environment variables and link the service runbook to the proxy error guide. A controlled migration is more reliable than setting HTTP_PROXY globally and hoping every dependency interprets it the same way.

Node.js proxy FAQ

Does Node.js fetch support HTTP_PROXY?

Current supported Node releases can use built-in environment proxy support when explicitly enabled. Check the runtime version and current Node documentation.

What is EnvHttpProxyAgent?

It is an Undici dispatcher that reads HTTP_PROXY, HTTPS_PROXY and NO_PROXY variables and routes supported requests accordingly.

Can Axios use a proxy?

Yes. In Node.js, Axios has request configuration for HTTP proxy host, port and authentication. SOCKS commonly needs a compatible custom agent.

Why is NO_PROXY important?

It defines destinations that bypass the proxy. Incorrect patterns can cause accidental direct traffic or send internal requests through an external route.

Should I set a global dispatcher and Axios proxy together?

Avoid overlapping mechanisms unless the precedence is deliberately tested. Choose one owner for routing in each code path.

How do I test the Node.js proxy route?

Request a controlled IP endpoint with a timeout, compare the observed exit with the assigned proxy, then test the authorized target and classify any failure.

Use tested proxies in reproducible developer workflows

Use one explicit routing owner per client, protect credentials, close agents cleanly and size proxy concurrency from real valid requests.

Scroll to Top