deps/undici/src/docs/docs/GettingStarted.md
npm install undici
The quickest way to get started is with fetch, which follows the
Fetch Standard and works the same way as
the browser API:
import { fetch } from 'undici'
const res = await fetch('https://example.com')
const data = await res.json()
console.log(data)
undici also exports a Request class that follows the Fetch Standard:
import { fetch, Request } from 'undici'
const req = new Request('https://example.com', {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ hello: 'world' })
})
const res = await fetch(req)
console.log(res.status)
res.body is a web ReadableStream. Use pipeline from
node:stream/promises to stream it to a file:
import { fetch } from 'undici'
import { pipeline } from 'node:stream/promises'
import { createWriteStream } from 'node:fs'
const res = await fetch('https://example.com/large-file.zip')
await pipeline(res.body, createWriteStream('./file.zip'))
Always consume or cancel the response body. In Node.js, garbage collection is not aggressive enough to release connections promptly, so leaving a body unread can cause connection leaks and stalled requests. See Specification Compliance - Garbage Collection for details.
For more on fetch, see API Reference: Fetch.
By default, fetch, request, stream, and pipeline create a new connection
for each call. For applications that make many requests to the same origin,
this is wasteful. undici provides dispatchers that manage connections
internally.
Agent — for requests to multiple originsAgent is the most general-purpose dispatcher. It pools connections per-origin
and is the recommended default for most applications. Use it with
setGlobalDispatcher to affect all undici calls globally:
import { Agent, setGlobalDispatcher, fetch } from 'undici'
const agent = new Agent({
keepAliveTimeout: 30_000,
keepAliveMaxTimeout: 600_000
})
setGlobalDispatcher(agent)
// All subsequent fetch/request/stream/pipeline calls reuse connections
const res = await fetch('https://api.example.com/data')
You can also pass a dispatcher per-request:
await fetch('https://api.example.com/data', { dispatcher: agent })
Pool — for requests to a single originPool manages a fixed set of connections to one origin. It gives you explicit
control over concurrency:
import { Pool, request } from 'undici'
const pool = new Pool('https://api.example.com', { connections: 10 })
const { body } = await request('https://api.example.com/data', {
dispatcher: pool
})
const data = await body.json()
pool.close()
Client — for a single connectionClient maps to a single TCP connection. It supports pipelining (sending
multiple requests before responses arrive):
import { Client } from 'undici'
const client = new Client('https://api.example.com', {
pipelining: 5
})
const { body } = await client.request({ path: '/', method: 'GET' })
await body.dump()
client.close()
For more on dispatcher options and lifecycle, see:
undici applies timeouts at two levels:
headersTimeout — time to wait for response headers (default: 300s).bodyTimeout — time between consecutive body chunks (default: 300s).Set these on the dispatcher or per-request:
import { Agent, setGlobalDispatcher } from 'undici'
const agent = new Agent({
headersTimeout: 5_000,
bodyTimeout: 30_000
})
setGlobalDispatcher(agent)
Timeout errors are thrown as HeadersTimeoutError and BodyTimeoutError.
See API Reference: Errors for the full list.
undici exposes structured errors via error.code:
import { request, errors } from 'undici'
try {
const { body } = await request('https://example.com')
await body.json()
} catch (err) {
switch (err.code) {
case 'UND_ERR_CONNECT_TIMEOUT':
console.error('Connection timed out')
break
case 'UND_ERR_HEADERS_TIMEOUT':
console.error('Headers timed out')
break
case 'UND_ERR_BODY_TIMEOUT':
console.error('Body timed out')
break
case 'UND_ERR_ABORTED':
console.error('Request was aborted')
break
default:
console.error(err)
}
}
import { request } from 'undici'
const ac = new AbortController()
setTimeout(() => ac.abort(), 1000)
try {
const { body } = await request('https://example.com', {
signal: ac.signal
})
await body.dump()
} catch (err) {
console.error(err.code) // UND_ERR_ABORTED
}
Use ProxyAgent for HTTP(S) proxies, or EnvHttpProxyAgent to pick up
proxy settings from environment variables:
import { ProxyAgent, setGlobalDispatcher } from 'undici'
const proxy = new ProxyAgent('http://proxy.internal:8080')
setGlobalDispatcher(proxy)
See Best Practices: Proxy and API Reference: ProxyAgent.
import { MockAgent, setGlobalDispatcher, request } from 'undici'
const mockAgent = new MockAgent()
setGlobalDispatcher(mockAgent)
const mockPool = mockAgent.get('https://api.example.com')
mockPool.intercept({ path: '/users' }).reply(200, [{ id: 1 }])
const { body } = await request('https://api.example.com/users')
console.log(await body.json())
See Best Practices: Mocking Request and API Reference: MockAgent.
For test suites, set short keep-alive timeouts to avoid slow teardowns:
import { Agent, setGlobalDispatcher } from 'undici'
const agent = new Agent({
keepAliveTimeout: 10,
keepAliveMaxTimeout: 10
})
setGlobalDispatcher(agent)
See Best Practices: Writing Tests.
You can override Node.js's built-in globals with install():
import { install } from 'undici'
install()
// Global fetch, Headers, Response, Request, and FormData
// now come from undici, not the Node.js bundle
const res = await fetch('https://example.com')
See API Reference: Global Installation.