mrkeyoor.com_
Sat 19 Sept 08:56 UTC
npmWeb Backendupdated 19 Sept 2026

undici review

Undici 8.10.0 installed as 1 dependency-free, 3 MB package in our Node 22 sandbox, and its browser bundle failed because the transport is Node-only. Node's built-in fetch already runs on a bundled Undici version. Installing this release adds direct request, stream, pipeline, Pool, Agent, proxy, mock, cache, retry, and interceptor APIs on npm's cadence. The lower-level request call returns status, headers, and a Node body. Version 8 requires Node 22.19 or newer and continues newer HTTP/2 work alongside its established HTTP/1.1 path.

166.5Mdownloads / wk
Verdict

Undici 8.10.0 installed in 0.4 seconds as 1 dependency-free, 3 MB package with 0 audit findings in our sandbox, while its browser build failed. Use native fetch for ordinary Node HTTP; install Undici for explicit pools, mocks, proxies, interceptors, or a measured request-path gain.

We installed it

Lab card: what happened when we installed undiciScreenshot of undici documentation
Install✓ · 0.4s1 package on disk · 3 MB
ImportESM import works · require() works · CommonJS package
Browsern/acould not be bundled for the browser (Node-only code, most likely)
TypesTypeScript types bundled
Known vulns00 critical · 0 high · 0 moderate · 0 low (npm audit)

Answers from our run

Does undici install cleanly?

Yes. In a fresh container with an empty cache, npm install undici finished in 0.4s, leaving 1 package and 3 MB on disk. npm audit reported no known vulnerabilities.

Can undici run in a browser?

Not directly: esbuild could not bundle it for the browser in our run, which normally means it depends on Node built-ins. Use it on the server, or find a browser-targeted alternative.

Does undici work with both ESM and CommonJS?

Yes. Both import 'undici' and require('undici') worked in Node 22 in our run. The package is published as CommonJS.

Does undici include TypeScript types?

Yes, type declarations ship inside the package, so no @types install is needed.

undici or got: which should you use?

got: Choose it for higher-level retries, lifecycle hooks, pagination, and a friendlier Node request API. Undici 8.10.0 installed in 0.4 seconds as 1 dependency-free, 3 MB package with 0 audit findings in our sandbox, while its browser build failed.

When should you not use undici?

Skip the dependency when global fetch handles ordinary requests and no dispatcher control is needed.

API stability4/5fetch follows the web platform, while Dispatcher, Agent, Pool, request, interceptors, and RetryAgent can change across Undici majors and Node support floors. The objects share one dispatch model, but version 8 already requires Node 22.19. Applications using advanced calls should pin the package and review migrations instead of assuming the standards-based fetch compatibility applies to every class.
Docs5/5The official documentation separates Node's bundled fetch from the npm package, compares request paths, and covers dispatchers, pools, proxy agents, mocks, retries, interceptors, caching, streams, diagnostics channels, and specification differences. Its README warns readers to consume response bodies and keep fetch and FormData implementations together, addressing 2 failure modes that short examples often omit.
Maintenance5/5npm lists 8.10.0, and GitHub showed a repository push on August 26, 2026, with 347 open issues and pull requests. The project lives under the Node organization and supplies the implementation behind the runtime's fetch. Current protocol, cache, and dispatcher work plus its runtime role support a 5 despite the sizable shared issue and PR queue.
Ecosystem5/5npm counted 168,588,680 downloads from August 19 through 25, 2026, and GitHub reports 7,682 stars. Direct package users get proxy, mock, retry, cache, and diagnostics components, while Node itself bundles Undici behind global fetch. The package adds those service-level controls without a native dependency, but they remain specific to Node rather than portable browser APIs.

Discussed on

  1. hnUndici – an HTTP/1.1 client, written from scratch for Node.js16 points
  2. hnHTTP Fundamentals: Understanding Undici and Its Working Mechanism4 points

Use it if

  • Use it when a Node service needs explicit dispatchers, pools, pipelining, or proxy agents.
  • Choose request() only after measurements show a useful advantage over the runtime's global fetch.
  • Install it when tests need MockAgent and a hard block on unplanned network access.
  • Adopt the package when a required Undici fix or feature is newer than the version bundled by Node.
Skip it if

Setup reality

We installed Undici 8.10.0 in 0.4 seconds in a clean Node 22 container. The result was 1 package using 3 MB; npm reports 2,428 KB unpacked. It has 0 direct dependencies and 0 peers, requires Node 22.19 or later, uses MIT, and bundles TypeScript types. npm audit found 0 vulnerabilities. The CommonJS package has no exports map. require() and ESM import worked. Our esbuild browser bundle failed, which is the expected Node-only outcome.

Global fetch already uses the Undici build shipped with Node and is enough for routine calls. The npm package makes sense for direct request performance, newer releases, explicit Agent or Pool behavior, interceptors, ProxyAgent, Socks5Agent, or MockAgent. Keep fetch and FormData from the same implementation; mixing global FormData with undici.fetch can create incompatible body handling.

Reuse a dispatcher rather than constructing one for every call. setGlobalDispatcher changes process-wide behavior, including other code using shared Undici globals, so a library should pass its own dispatcher. Tune connections and pipelining against a real origin. headersTimeout and bodyTimeout measure separate phases, not total elapsed time; use AbortSignal for the caller's overall cancellation policy.

Consume, dump, cancel, or finish every response body so its connection can return to the pool. Check status before JSON parsing. RetryAgent needs a bounded budget and a method policy that will not repeat side effects; honor Retry-After where applicable. MockAgent.disableNetConnect should be undone with global state restoration after tests. HTTP/2 is newer than the HTTP/1.1 implementation, so test negotiation and server behavior before relying on it.

Patterns

Read JSON through the request API get-json

import { request } from 'undici'

const { statusCode, headers, body } = await request('https://api.example.com/data')
if (statusCode !== 200) {
  await body.dump()
  throw new Error(`unexpected status ${statusCode}`)
}
const data = await body.json()

body.dump handles the non-200 path so that connection can return to its dispatcher pool.

Post an explicitly encoded JSON object post-json

import { request } from 'undici'

const { statusCode, body } = await request('https://api.example.com/items', {
  method: 'POST',
  headers: { 'content-type': 'application/json' },
  body: JSON.stringify({ name: 'widget', qty: 2 })
})
const created = await body.json()

request accepts the serialized string and does not turn an object into JSON. The content-type header is also the caller's responsibility.

Call the package-level fetch fetch-drop-in

import { fetch } from 'undici'

const res = await fetch('https://api.example.com/data')
if (!res.ok) throw new Error(`HTTP ${res.status}`)
const data = await res.json()

Import FormData from the same source as fetch when sending forms. Mixed implementations can disagree on body handling.

Replace the dispatcher for the whole process connection-pool

import { Agent, setGlobalDispatcher } from 'undici'

setGlobalDispatcher(new Agent({
  connections: 128,
  keepAliveTimeout: 10_000,
  pipelining: 1
}))
// every undici request/fetch in the process now uses this pool

All Undici consumers that share the global now inherit 128 connections and this keep-alive policy. Library code should pass a local dispatcher.

Retry a bounded set of response statuses http-retry

import { Agent, RetryAgent, request } from 'undici'

const agent = new RetryAgent(new Agent(), {
  maxRetries: 3,
  minTimeout: 500,
  statusCodes: [429, 500, 502, 503, 504]
})
const { statusCode, body } = await request('https://api.example.com/flaky', {
  dispatcher: agent
})

A 3-retry policy can repeat writes. Limit it to idempotent methods unless the server honors an idempotency key, and add an overall deadline.

Send one request through ProxyAgent proxy

import { ProxyAgent, request } from 'undici'

const proxy = new ProxyAgent('http://proxy.internal:8080')
const { body } = await request('https://api.example.com/data', {
  dispatcher: proxy
})
const data = await body.json()

Close proxy during application shutdown so sockets do not linger. Redact any credentials embedded in its URL from logs.

Fail tests that miss their HTTP mock mock-testing

import { MockAgent, setGlobalDispatcher, request } from 'undici'

const mockAgent = new MockAgent()
mockAgent.disableNetConnect()
setGlobalDispatcher(mockAgent)

mockAgent
  .get('https://api.example.com')
  .intercept({ path: '/users/1', method: 'GET' })
  .reply(200, { id: 1, name: 'ada' })

const { body } = await request('https://api.example.com/users/1')
console.log(await body.json()) // { id: 1, name: 'ada' }

disableNetConnect turns an unmatched request into a failure. Restore the previous global dispatcher after the case to avoid contaminating another suite.

Bound response-header wait and body inactivity timeouts

import { Agent, request } from 'undici'

const agent = new Agent({
  headersTimeout: 10_000, // ms to wait for response headers
  bodyTimeout: 30_000     // ms of body inactivity allowed
})
const { body } = await request('https://api.example.com/slow', {
  dispatcher: agent
})

The 10,000 ms and 30,000 ms limits cover separate phases. An AbortSignal is still needed for one end-to-end caller deadline.

Alternatives

PackageRegistryPick it when
gotnpmChoose it for higher-level retries, lifecycle hooks, pagination, and a friendlier Node request API.
axiosnpmChoose it when one browser and Node client plus interceptors matters more than dispatcher-level control.
node-fetchnpmKeep it for older Node releases or an application already tied to node-fetch extensions and stream behavior.

More web backend guides

urllib3 · requests · ws · anyio · httpx · express · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.