What Is Node.js Proxy & How to Use Proxy Servers in Node.js
TL;DR
Node.js has no built-in proxy support. Core http/https modules send requests directly to the destination host unless you attach a proxy-aware http.Agent or set the request options yourself.
HTTP_PROXY/HTTPS_PROXY environment variables only work if the library you call reads them. Core http.request ignores them entirely; most CLI tools and some HTTP clients read them through helper packages, not automatically.
https-proxy-agent and http-proxy-agent are the standard way to route core http/https requests through a proxy, using an HTTP CONNECT tunnel for HTTPS targets and direct relaying for HTTP targets.
Axios accepts a proxy object directly (host, port, protocol, optional auth), so most Axios-based projects don't need a separate agent package for HTTP proxies.
Native fetch and undici route through a proxy via and , which also affects Node's global since Node 18+ built it on undici.
Proxy credentials belong in the proxy URL or a dedicated auth field, never hardcoded in application code that gets committed to source control.
SOCKS5 proxies need a different agent (socks-proxy-agent) because the CONNECT-based HTTP proxy agents don't speak the SOCKS handshake.
Introduction: what "proxy" means for a Node.js request
A proxy in Node.js is an intermediary server that a script deliberately routes an outbound HTTP or HTTPS request through, instead of connecting straight to the destination host. Node's core http and https modules were not built with proxy support as a default behavior — every proxied request in Node.js works because the code (or a library) explicitly points the request at a proxy host, either through a custom http.Agent or through client-specific configuration.
That distinction matters because it explains why copying a proxy tutorial written for one HTTP client into a project using a different client often does nothing. curl and many system tools read HTTP_PROXY/HTTPS_PROXY from the environment automatically; Node's http.request does not. Each client library below needs its own explicit setup.
Take a Quick Look
Wiring proxy credentials and rotation logic into every request is easy to get wrong by hand — Nstproxy issues a stable gateway endpoint per plan so your Node.js code only has to point at one proxy URL.
Node.js ships http, https, and (from Node 18 onward) a global fetch backed by undici's ProxyAgent. None of them include proxy-routing code, so add the agent package that matches the client you already use:
You don't need all five in one project — install only the packages for the client(s) your code actually calls. https-proxy-agent version 9.1.0 and http-proxy-agent version 9.1.0 both export a named class (HttpsProxyAgent, HttpProxyAgent) rather than a default export, which matters for the require/import syntax below.
Configure a proxy for Node's core http/https modules
http-proxy-agent relays plain HTTP requests through the proxy; https-proxy-agent opens an HTTP CONNECT tunnel through the proxy and then negotiates TLS with the destination, which is what an HTTPS target requires. Passing the resulting agent as the agent option on Node's http.Agent-based request functions is the only change to an otherwise normal https.request call:
This example was run against a local test proxy (a Node http.createServer handling CONNECT) and a local HTTPS target: the request returned 200 and the expected JSON body through the tunnel, confirming the CONNECT-then-TLS flow works with this exact agent version and call shape.
For a plain HTTP (not HTTPS) destination, use HttpProxyAgent instead — it relays the request without a CONNECT handshake:
Running an unmodified http.get() call against the same target with no agent option, and with HTTP_PROXY set only as an environment variable, confirmed that core http ignores the environment variable — the request went straight to the target instead of through the proxy. Treat any tutorial that tells you to "just set HTTP_PROXY" for core http/https as incomplete; it works only for tools that specifically read that variable.
Configure a proxy in Axios
Axios (tested at version 1.19.0) accepts proxy settings as a plain object on the request config, with no extra agent package required for HTTP-scheme proxies:
This request was run against the same local proxy and target used above and returned 200 with the expected body, confirming Axios's proxy option performs the CONNECT tunnel for an HTTPS target on its own. If you need TLS options Axios's proxy object doesn't expose — a custom CA, or disabling certificate verification against an internal test host — pass httpsAgent: new https.Agent({...}) alongside proxy, or replace proxy entirely with an https-proxy-agent instance assigned to httpsAgent.
Axios also honors HTTP_PROXY/HTTPS_PROXY/NO_PROXY environment variables by default, unless proxy: false is set in the request config — this is one of the few clients where the environment-variable convention works without you writing agent code.
Configure a proxy for node-fetch and native fetch/undici
node-fetch (tested at version 2.7.0) takes the same agent option as core http/https, so the same http-proxy-agent/https-proxy-agent instances apply:
Run against the local test proxy and an HTTP target, this returned the expected JSON body, confirming the same agent classes work unchanged across core http and node-fetch.
Node's built-in global fetch() (available from Node 18 onward) and the standalone undici package don't accept an agent option the same way — they use undici's own ProxyAgent, registered globally with setGlobalDispatcher:
const{ProxyAgent, setGlobalDispatcher }=require('undici');setGlobalDispatcher(newProxyAgent('http://proxy.example.com:8000'));const res =awaitfetch('https://api.example.com/status');console.log(res.status,await res.json());
This was run with undici version 6.28.0: after calling setGlobalDispatcher, both undici.request() and Node's global fetch() routed through the local test proxy and returned the expected 200 response — confirming setGlobalDispatcher affects global fetch, not just undici's own request functions, because Node's fetch implementation is built on undici. Scope a ProxyAgent to a single request instead of setting it globally when only some requests in a process need to go through the proxy — pass { dispatcher: new ProxyAgent(...) } as a per-call option to undici.request().
Advanced patterns: authentication, SOCKS5, and rotation
Proxy authentication. For all four clients above, embed credentials in the proxy URL (http://user:pass@proxy.example.com:8000) or the client's dedicated auth field (Axios's proxy.auth). Never format them into the target request's own Authorization header — that header goes to the destination server, not the proxy, and most proxy servers expect credentials in a Proxy-Authorization header, which the agent packages construct for you from the URL's userinfo.
SOCKS5 proxies.https-proxy-agent and http-proxy-agent only implement the HTTP CONNECT proxy protocol. A SOCKS5 endpoint needs socks-proxy-agent, which exposes the same agent option pattern:
Session control (sticky vs. rotating). Whether a given request reuses the same exit IP as the previous one, or gets a new one, is controlled by the proxy provider's gateway, not by Node.js — the client-side code above stays identical either way. Providers that support both modes typically switch behavior based on a session parameter appended to the proxy username (a "sticky session" ID) or on separate gateway ports for sticky vs. rotating pools; check the specific provider's gateway documentation for the exact parameter name before assuming a convention from one provider applies to another.
Using Nstproxy with the same patterns
Nstproxy provides HTTP/SOCKS5 gateway endpoints across Residential Lite Proxies and six other proxy product lines — Residential Prime, Datacenter, Static ISP, IPv6, Unlimited Residential, and Mobile — so the same HttpsProxyAgent/Axios proxy/ProxyAgent code above works by pointing the agent at your assigned Nstproxy gateway host, port, and credentials instead of a placeholder. Nstproxy is built for teams that need geographic targeting, session control, or higher request volume than a single self-hosted proxy can sustain, and it fits scraping, price-monitoring, ad verification, and QA testing workloads where a single exit IP would get rate-limited or blocked.
Country- and city-level targeting — select an exit location by including a location parameter in the proxy username, without changing any client-side request code.
Sticky or rotating sessions — hold one IP for a multi-step workflow (login, then paginate) or rotate per request, depending on the session parameter used.
HTTP and SOCKS5 gateways — the same client code shown above (agent-based for core http/node-fetch, native proxy object for Axios, ProxyAgent for undici/fetch) works against Nstproxy's gateway without further changes.
Confirm current gateway hostnames, ports, and pricing on the Residential Lite Proxies pricing page before provisioning, since gateway details and rates are subject to change. Full gateway parameters, authentication formats, and SDK snippets are in the Nstproxy documentation; if you're deciding between proxy providers first, the Nstproxy proxy comparison page lays out feature differences against other providers. Teams that pair proxy traffic with a Node.js crawler often centralize routing rules and pool monitoring next — see how Nstproxy Proxy Manager applies to crawling workloads for that layer.
Honest limits
Core http/https and node-fetch never read HTTP_PROXY/HTTPS_PROXY on their own — every example above sets the proxy explicitly in code, and any deployment relying on the environment variable alone for these clients will silently bypass the proxy.
https-proxy-agent's CONNECT tunnel adds one extra network round trip per new HTTPS connection compared to a direct request; connection reuse (keepAlive: true on the agent) amortizes that cost across multiple requests to the same host.
None of the agent packages above retry a failed proxy connection or rotate to a different exit IP automatically — that logic, if you need it, has to be written into your own request wrapper or provided by the proxy service's gateway.
WebSocket connections need their own proxy-aware upgrade handling; the agents shown here cover plain HTTP/HTTPS request/response cycles, not the Upgrade handshake.
Troubleshooting
ECONNREFUSED or ECONNRESET when connecting through the proxy. Confirm the proxy host and port are reachable directly (for example with nc -vz host port) before assuming the Node.js code is wrong — a firewall or an expired proxy session produces the same error as a code bug.
unable to verify the first certificate or self-signed certificate errors. This means the client is validating TLS for the destination host through the tunnel and failing, usually because a corporate or testing proxy is intercepting TLS with its own certificate. Add that certificate to Node's trusted store (NODE_EXTRA_CA_CERTS) rather than disabling certificate validation in production code.
Requests hang instead of failing. Set an explicit timeout on the agent or the client (timeout option on http.request, timeout on Axios) — proxies that silently drop packets instead of returning a connection-refused error will otherwise hang until the platform's default socket timeout.
Only some requests use the proxy. For undici/global fetch, setGlobalDispatcher applies to every subsequent call in the process; if some calls bypass the proxy unexpectedly, check whether that code path uses a different HTTP client (Axios, node-fetch) that needs its own separate proxy configuration.
Conclusion
Every proxy setup in Node.js comes down to the same decision: which HTTP client is making the request, and which of that client's supported proxy mechanisms — an explicit http.Agent, a proxy config object, or a global dispatcher — you configure with the destination host, port, and credentials. Core http/https and node-fetch need an agent from https-proxy-agent/http-proxy-agent/socks-proxy-agent; Axios accepts a proxy object directly; native fetch and undici route through ProxyAgent and setGlobalDispatcher. None of them work through the HTTP_PROXY environment variable alone unless the specific client documents that it reads it.
FAQ
Q: Does Node.js support proxies out of the box?
No — core http and https modules connect directly to the destination host unless the request explicitly uses a proxy-aware http.Agent (from a package like https-proxy-agent) or the client library has its own proxy configuration, like Axios's proxy option.
Q: Why doesn't setting HTTP_PROXY work in my Node.js script?
Setting HTTP_PROXY only works for clients that specifically read it — Axios reads it by default, but core http/https and node-fetch do not, so those need an explicit agent in code regardless of environment variables.
Q: What's the difference between http-proxy-agent and https-proxy-agent?
http-proxy-agent relays a plain HTTP request through the proxy without a tunnel, while https-proxy-agent opens an HTTP CONNECT tunnel through the proxy first and then negotiates TLS with the HTTPS destination — use the one that matches your target's scheme, not your proxy's scheme.
Q: Can I use a proxy with Node's native fetch()?
Yes — register an undici ProxyAgent with setGlobalDispatcher() before calling fetch(), since Node's built-in fetch runs on undici and reads the same global dispatcher.
Q: Do I need a different setup for a SOCKS5 proxy?
Yes — https-proxy-agent and http-proxy-agent only implement the HTTP CONNECT proxy protocol, so a SOCKS5 endpoint needs socks-proxy-agent instead, using the same agent option pattern.
Q: Is it safe to hardcode proxy credentials in my Node.js code?
No — keep proxy usernames and passwords in environment variables or a secrets manager and build the proxy URL at runtime, the same way you'd handle a database password, rather than committing them into source control.
Q: Will a proxy slow down my Node.js requests?
An HTTPS request through an HTTP CONNECT tunnel adds one extra round trip to establish the tunnel compared to a direct connection, but enabling keepAlive on the agent lets subsequent requests to the same host reuse that tunnel instead of paying the cost again.
Ivy Lin
Aug. 7th 2026
110M+ real IPs with 99.9% access success
Blazing-fast average response ~0.5s for high-concurrency tasks
From only $0.1/GB
Get immediate access to premium residential, datacenter, IPv6 and ISP proxy pools.