Node.js has shipped a built-inDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/nodejs/undici/llms.txt
Use this file to discover all available pages before exploring further.
fetch() implementation powered by undici since Node.js v18. Both options share the same underlying HTTP engine, but they expose different capabilities. This guide explains the differences, shows the performance data, and helps you decide which to use for your project.
Background: they share the same engine
Thefetch(), Request, Response, Headers, and FormData globals in Node.js v18+ come from a version of undici that is bundled directly into the Node.js binary. Installing undici from npm gives you the same library — but potentially a newer release — plus all of its additional APIs that are not exposed as globals.
You can check which version of undici is currently bundled with your Node.js runtime:
Checking the bundled undici version
Comparison
| Feature | Built-in fetch | undici module |
|---|---|---|
| Standard Fetch API | Yes | Yes |
request() / stream() / pipeline() | No | Yes |
ProxyAgent / Socks5ProxyAgent | No | Yes |
MockAgent / MockClient / MockPool | No | Yes |
EnvHttpProxyAgent | No | Yes (--use-env-proxy in Node.js v22.21+) |
| Custom interceptors | No | Yes |
| Connection pool configuration | No | Yes |
| HTTP/1.1 pipelining | No | Yes |
WebSocket / EventSource | Yes (Node.js v22+) | Yes |
| Always uses latest undici | No | Yes |
| Zero additional dependencies | Yes | No |
| Runs in browsers / Deno / Bun | Yes | No |
Performance comparison
The benchmark below was run with 50 TCP connections and a pipelining depth of 10 on Node.js 22.11.0. All three undici APIs outperform the built-inhttp module with keep-alive, and undici.request() reaches over 18,000 req/sec — more than 3x the throughput of axios or node-fetch:
| Client | Requests/sec | vs. slowest |
|---|---|---|
| axios | 5,708 | baseline |
| node-fetch | 5,945 | +4.15% |
| undici fetch | 5,903 | +3.43% |
| http (keepalive) | 9,193 | +61.05% |
| undici pipeline | 13,364 | +134.13% |
| undici stream | 18,245 | +219.63% |
| undici request | 18,340 | +221.29% |
| undici dispatch | 22,234 | +289.51% |
undici.fetch() and the built-in global fetch perform similarly. The speed advantage of the undici module comes from request(), stream(), and pipeline(), which bypass the Web Streams layer.When to use the built-in globals
You do not need to install undici when all of the following are true:- You only need the standard Fetch API (
fetch,Request,Response,Headers,FormData). - You are running Node.js v18 or later.
- You do not depend on features or bug fixes from a newer undici release than the one bundled with your Node.js version.
- You want zero additional runtime dependencies.
- You are writing isomorphic code that also runs in browsers, Deno, Bun, or Cloudflare Workers.
Using the built-in fetch globally (Node.js v18+)
When to install the undici module
Install undici from npm when you need any of the following:Higher-performance request APIs
Higher-performance request APIs
request(), stream(), and pipeline() provide lower-level access and significantly better throughput than fetch(). Use them for high-volume services or data-intensive workloads.Using request() for performance
Connection pooling and dispatcher configuration
Connection pooling and dispatcher configuration
Client, Pool, BalancedPool, Agent, and their options let you control keep-alive behavior, pipelining depth, and concurrency per origin.Configuring a connection pool
Proxy support
Proxy support
ProxyAgent and EnvHttpProxyAgent provide full programmatic proxy configuration. While Node.js v22.21.0+ supports --use-env-proxy for built-in fetch, undici’s ProxyAgent gives you per-request dispatcher control.Routing through a proxy
Mocking and testing
Mocking and testing
MockAgent, MockClient, and MockPool let you intercept and assert on HTTP traffic in tests without running a real server or patching globals.Mocking with MockAgent
Custom interceptors and middleware
Custom interceptors and middleware
Compose interceptors for caching, retry, DNS, redirect, and deduplication on any dispatcher without modifying request call sites.
Composing interceptors
Migration: from built-in fetch to undici
If you are currently using the built-in globalfetch and want to migrate to undici, here are your options in increasing order of performance:
Drop-in fetch replacement
Importfetch from undici instead of using the global. The API is identical:
Switching to undici fetch
Migrate to request() for better performance
request() returns statusCode, headers, and body directly — no Response wrapper — which eliminates the Web Streams overhead:
Migrating from fetch to request()
Replace the global dispatcher
To use undici’sfetch globally (replacing the built-in), call install():
Replacing global fetch with undici
Keep fetch and FormData from the same implementation
When uploadingFormData, use a consistent pair. Pick one of these patterns:
- Built-in globals
- undici imports
- install() globals
Using built-in FormData with built-in fetch
Version compatibility table
| Node.js version | Bundled undici | fetch status | Notes |
|---|---|---|---|
| v18.x | ~5.x | Experimental (early), then stable | Behind --experimental-fetch in early v18 |
| v20.x | ~6.x | Stable | |
| v22.x | ~6.x / ~7.x | Stable | --use-env-proxy in v22.21.0+ |
| v24.x | ~7.x | Stable | --use-env-proxy enabled by default |
install() if you want your installed version to replace globalThis.fetch and friends. Otherwise, import directly:
Importing undici fetch explicitly