MCPcopy
hub / github.com/nodejs/undici

github.com/nodejs/undici @v8.6.0 sqlite

repository ↗ · DeepWiki ↗ · release v8.6.0 ↗
2,743 symbols 9,408 edges 669 files 549 documented · 20%
README

undici

Node CI neostandard javascript style npm version codecov

An HTTP/1.1 client, written from scratch for Node.js.

Undici means eleven in Italian. 1.1 -> 11 -> Eleven -> Undici. It is also a Stranger Things reference.

How to get involved

Have a question about using Undici? Open a Q&A Discussion or join our official OpenJS Slack channel.

Looking to contribute? Start by reading the contributing guide

Install

npm i undici

Benchmarks

The benchmark is a simple getting data example using 50 TCP connections with a pipelining depth of 10 running on Node 24.14.1.

HTTP/1.1

┌────────────────────────┬─────────┬────────────────────┬────────────┬─────────────────────────┐
│  Tests                 │ Samples │ Result             │ Tolerance  │ Difference with slowest │
├────────────────────────┼─────────┼────────────────────┼────────────┼─────────────────────────┤
│  'node-fetch'          │ 50      │ '4711.86 req/sec'  │ '± 2.92 %' │ '-'                     │
│  'undici - fetch'      │ 75      │ '5438.50 req/sec'  │ '± 2.97 %' │ '+ 15.42 %'             │
│  'axios'               │ 45      │ '5448.08 req/sec'  │ '± 2.98 %' │ '+ 15.62 %'             │
│  'request'             │ 65      │ '5809.63 req/sec'  │ '± 2.90 %' │ '+ 23.30 %'             │
│  'http - no keepalive' │ 35      │ '5910.77 req/sec'  │ '± 2.87 %' │ '+ 25.44 %'             │
│  'got'                 │ 50      │ '6047.80 req/sec'  │ '± 2.91 %' │ '+ 28.35 %'             │
│  'superagent'          │ 60      │ '7534.53 req/sec'  │ '± 2.97 %' │ '+ 59.91 %'             │
│  'http - keepalive'    │ 75      │ '9343.41 req/sec'  │ '± 2.90 %' │ '+ 98.30 %'             │
│  'undici - pipeline'   │ 65      │ '13470.70 req/sec' │ '± 2.93 %' │ '+ 185.89 %'            │
│  'undici - request'    │ 80      │ '16850.87 req/sec' │ '± 2.93 %' │ '+ 257.63 %'            │
│  'undici - stream'     │ 101     │ '18488.56 req/sec' │ '± 3.81 %' │ '+ 292.38 %'            │
│  'undici - dispatch'   │ 101     │ '20786.44 req/sec' │ '± 3.08 %' │ '+ 341.15 %'            │
└────────────────────────┴─────────┴────────────────────┴────────────┴─────────────────────────┘

HTTP/1.1 over HTTPS

Using benchmark-https.js against an h1-over-TLS server (50 connections, pipelining depth 10, Node 24.14.1).

┌────────────────────────┬─────────┬───────────────────┬────────────┬─────────────────────────┐
│  Tests                 │ Samples │ Result            │ Tolerance  │ Difference with slowest │
├────────────────────────┼─────────┼───────────────────┼────────────┼─────────────────────────┤
│  'https - no keepalive'│ 10      │ '1358.40 req/sec' │ '± 1.99 %' │ '-'                     │
│  'undici - fetch'      │ 30      │ '3721.76 req/sec' │ '± 2.97 %' │ '+ 173.98 %'            │
│  'https - keepalive'   │ 35      │ '5633.91 req/sec' │ '± 2.84 %' │ '+ 314.75 %'            │
│  'undici - pipeline'   │ 15      │ '6254.05 req/sec' │ '± 2.80 %' │ '+ 360.40 %'            │
│  'undici - request'    │ 25      │ '6669.80 req/sec' │ '± 2.73 %' │ '+ 391.01 %'            │
│  'undici - stream'     │ 25      │ '7019.04 req/sec' │ '± 2.77 %' │ '+ 416.71 %'            │
│  'undici - dispatch'   │ 20      │ '7361.85 req/sec' │ '± 2.90 %' │ '+ 441.95 %'            │
└────────────────────────┴─────────┴───────────────────┴────────────┴─────────────────────────┘

HTTP/2

Using benchmark-http2.js against an h2 server (50 connections, pipelining depth 10, Node 24.14.1).

┌────────────────────────┬─────────┬───────────────────┬────────────┬─────────────────────────┐
│  Tests                 │ Samples │ Result            │ Tolerance  │ Difference with slowest │
├────────────────────────┼─────────┼───────────────────┼────────────┼─────────────────────────┤
│  'undici - fetch'      │ 45      │ '3499.03 req/sec' │ '± 2.93 %' │ '-'                     │
│  'native - http2'      │ 25      │ '4904.58 req/sec' │ '± 2.81 %' │ '+ 40.17 %'             │
│  'undici - pipeline'   │ 60      │ '5836.82 req/sec' │ '± 2.99 %' │ '+ 66.81 %'             │
│  'undici - request'    │ 65      │ '6831.25 req/sec' │ '± 2.83 %' │ '+ 95.23 %'             │
│  'undici - stream'     │ 55      │ '6874.30 req/sec' │ '± 2.91 %' │ '+ 96.46 %'             │
│  'undici - dispatch'   │ 55      │ '7791.23 req/sec' │ '± 2.96 %' │ '+ 122.67 %'            │
└────────────────────────┴─────────┴───────────────────┴────────────┴─────────────────────────┘

Undici vs. Fetch

Overview

Node.js includes a built-in fetch() implementation powered by undici starting from Node.js v18. However, there are important differences between using the built-in fetch and installing undici as a separate module.

Built-in Fetch (Node.js v18+)

Node.js's built-in fetch is powered by a bundled version of undici:

// Available globally in Node.js v18+
const response = await fetch('https://api.example.com/data');
const data = await response.json();

// Check the bundled undici version
console.log(process.versions.undici); // e.g., "5.28.4"

Pros: - No additional dependencies required - Works across different JavaScript runtimes - Automatic compression handling (gzip, deflate, br) - Built-in caching support (in development)

Cons: - Limited to the undici version bundled with your Node.js version - Less control over connection pooling and advanced features - Error handling follows Web API standards (errors wrapped in TypeError) - Performance overhead due to Web Streams implementation

Undici Module

Installing undici as a separate module gives you access to the latest features and APIs:

npm install undici
import { request, fetch, Agent, setGlobalDispatcher } from 'undici';

// Use undici.request for maximum performance
const { statusCode, headers, body } = await request('https://api.example.com/data');
const data = await body.json();

// Or use undici.fetch with custom configuration
const agent = new Agent({ keepAliveTimeout: 10000 });
setGlobalDispatcher(agent);
const response = await fetch('https://api.example.com/data');

Pros: - Latest undici features and bug fixes - Access to advanced APIs (request, stream, pipeline) - Fine-grained control over connection pooling - Better error handling with clearer error messages - Superior performance, especially with undici.request - HTTP/1.1 pipelining support - Custom interceptors and middleware - Advanced features like ProxyAgent, Socks5Agent, MockAgent

Cons: - Additional dependency to manage - Larger bundle size

When to Use Each

Use Built-in Fetch When:

  • You want zero dependencies
  • Building isomorphic code that runs in browsers and Node.js
  • Publishing to npm and want to maximize compatibility with JS runtimes
  • Simple HTTP requests without advanced configuration
  • You're publishing to npm and you want to maximize compatiblity
  • You don't depend on features from a specific version of undici

Use Undici Module When:

  • You need the latest undici features and performance improvements
  • You require advanced connection pooling configuration
  • You need APIs not available in the built-in fetch (ProxyAgent, Socks5Agent, MockAgent, etc.)
  • Performance is critical (use undici.request for maximum speed)
  • You want better error handling and debugging capabilities
  • You need HTTP/1.1 pipelining or advanced interceptors
  • You prefer decoupled protocol and API interfaces

Performance Comparison

Based on benchmarks, here's the typical performance hierarchy:

  1. undici.request() - Fastest, most efficient
  2. undici.fetch() - Good performance, standard compliance
  3. Node.js http/https - Baseline performance

Migration Guide

If you're currently using built-in fetch and want to migrate to undici:

// Before: Built-in fetch
const response = await fetch('https://api.example.com/data');

// After: Undici fetch (drop-in replacement)
import { fetch } from 'undici';
const response = await fetch('https://api.example.com/data');

// Or: Undici request (better performance)
import { request } from 'undici';
const { statusCode, body } = await request('https://api.example.com/data');
const data = await body.json();

Keep fetch and FormData together

When you send a FormData body, keep fetch and FormData from the same implementation.

Use one of these patterns:

// Built-in globals
const body = new FormData()
body.set('name', 'some')
await fetch('https://example.com', {
  method: 'POST',
  body
})
// undici module imports
import { fetch, FormData } from 'undici'

const body = new FormData()
body.set('name', 'some')
await fetch('https://example.com', {
  method: 'POST',
  body
})

If you want the installed undici package to provide the globals, call install() first:

import { install } from 'undici'

install()

const body = new FormData()
body.set('name', 'some')
await fetch('https://example.com', {
  method: 'POST',
  body
})

install() replaces the global fetch, Headers, Response, Request, and FormData implementations with undici's versions, so they all match. It also installs undici's WebSocket, CloseEvent, ErrorEvent, MessageEvent, and EventSource globals.

Avoid mixing a global FormData with undici.fetch(), or undici.FormData with the built-in global fetch().

Version Compatibility

You can check which version of undici is bundled with your Node.js version:

console.log(process.versions.undici);

Installing undici as a module allows you to use a newer version than what's bundled with Node.js, giving you access to the latest features and performance improvements.

Quick Start

Basic Request

import { request } from 'undici'

const {
  statusCode,
  headers,
  trailers,
  body
} = await request('http://localhost:3000/foo')

console.log('response received', statusCode)
console.log('headers', headers)

for await (const data of body) { console.log('data', data) }

console.log('trailers', trailers)

Using Cache Interceptor

Undici provides a powerful HTTP caching interceptor that follows HTTP caching best practices. Here's how to use it:

import { fetch, Agent, interceptors, cacheStores } from 'undici';

// Create a client with cache interceptor
const client = new Agent().compose(interceptors.cache({
  // Optional: Configure cache store (defaults to MemoryCacheStore)
  store: new cacheStores.MemoryCacheStore({
    maxSize: 100 * 1024 * 1024, // 100MB
    maxCount: 1000,
    maxEntrySize: 5 * 1024 * 1024 // 5MB
  }),

  // Optional: Specify which HTTP methods to cache (default: ['GET', 'HEAD'])
  methods: ['GET', 'HEAD']
}));

// Set the global dispatcher to use our caching client
setGlobalDispatcher(client);

// Now all fetch requests will use the cache
async function getData() {
  const response = await fetch('https://api.example.com/data');
  // The server should set appropriate Cache-Control headers in the response
  // which the cache will respect based on the cache policy
  return response.json();
}

// First request - fetches from origin
const data1 = await getData();

// Second request - served from cache if within max-age
const data2 = await getData();

Key Features:

  • Automatic Caching: Respects Cache-Control and Expires headers
  • Validation: Supports ETag and Last-Modified validation
  • Storage Options: In-memory or persistent SQLite storage
  • Flexible: Configure cache size, TTL, and more

Global Installation

Undici provides an install() function to add fetch-related and other web API classes to globalThis, making them available globally:

import { install } from 'undici'

// Install undici's global web APIs
install()

// Now you can use fetch classes globally without importing
const response = await fetch('https://api.example.com/data')
const data = await response.json()

// All classes are available globally:
const headers = new Headers([['content-type', 'application/json']])
const request = new Request('https://example.com')
const formData = new FormData()
const ws = new WebSocket('wss://example.com')
const eventSource = new EventSource('https://example.com/events')

The install() function adds the following classes to globalThis:

  • fetch - The fetch function
  • Headers - HTTP headers management
  • Response - HTTP response representation
  • Request - HTTP request representation
  • FormData - Form data handling
  • WebSocket - WebSocket client
  • CloseEvent, ErrorEvent, MessageEvent - WebSocket events
  • EventSource - Server-sent events client

When you call install(), these globals come from the same undici implementation. For example, global fetch and global FormData will both be undici's versions, and WebSocket and EventSource will also come from undici, which is the recommended setup if you want to use undici through globals.

This is useful for: - Polyfilling environments that don't have fetch - Ensuring consistent fetch behavior across different Node.js versions - Making undici's implementations available globally for libraries that expect them

Body Mixins

The `bod

Extension points exported contracts — how you extend this code

WebSocketStream (Interface)
(no doc) [20 implementers]
types/websocket.d.ts
CacheStore (Interface)
(no doc) [5 implementers]
types/cache-interceptor.d.ts
Interceptable (Interface)
(no doc) [4 implementers]
types/mock-interceptor.d.ts
BodyMixin (Interface)
* @link https://fetch.spec.whatwg.org/#body-mixin [1 implementers]
types/dispatcher.d.ts
SpecIterableIterator (Interface)
(no doc) [2 implementers]
types/fetch.d.ts
PendingInterceptorsFormatter (Interface)
(no doc) [1 implementers]
types/mock-agent.d.ts
CacheStorage (Interface)
(no doc) [1 implementers]
types/cache.d.ts
Options (Interface)
(no doc)
types/pool.d.ts

Core symbols most depended-on inside this repo

close
called by 2075
types/websocket.d.ts
ok
called by 1358
lib/web/fetch/response.js
end
called by 1215
test/http2-late-data.js
on
called by 1155
test/socks5-client.js
listen
called by 1104
test/fixtures/socks5-test-server.js
request
called by 961
test/http2-late-data.js
createServer
called by 871
test/connect-h2-alpn-order.js
text
called by 590
types/dispatcher.d.ts

Shape

Method 1,083
Function 1,079
Class 468
Interface 113

Languages

TypeScript100%

Modules by API surface

lib/core/errors.js128 symbols
lib/dispatcher/client-h2.js70 symbols
lib/web/fetch/util.js64 symbols
lib/dispatcher/client-h1.js53 symbols
types/errors.d.ts50 symbols
types/webidl.d.ts49 symbols
lib/core/util.js49 symbols
lib/web/fetch/index.js42 symbols
types/dispatcher.d.ts39 symbols
lib/web/fetch/request.js35 symbols
docs/examples/proxy/proxy.js35 symbols
lib/web/fetch/headers.js34 symbols

Dependencies from manifests, versioned

@fastify/busboy3.2.0 · 1×
@matteo.collina/tspl0.2.0 · 1×
@metcoder95/https-pem1.0.0 · 1×
@sinonjs/fake-timers12.0.0 · 1×
@types/node22.0.0 · 1×
abort-controller3.0.0 · 1×
axios1.6.7 · 1×
borp1.0.0 · 1×
c811.0.0 · 1×
concurrently10.0.3 · 1×
cronometro6.0.3 · 1×
cross-env10.0.0 · 1×

For agents

$ claude mcp add undici \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact