Back to Node

Getting Started

deps/undici/src/docs/docs/GettingStarted.md

26.3.16.9 KB
Original Source

Getting Started

Installation

bash
npm install undici

Fetch

The quickest way to get started is with fetch, which follows the Fetch Standard and works the same way as the browser API:

js
import { fetch } from 'undici'

const res = await fetch('https://example.com')
const data = await res.json()
console.log(data)

Using the Request object

undici also exports a Request class that follows the Fetch Standard:

js
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)

Streaming the response

res.body is a web ReadableStream. Use pipeline from node:stream/promises to stream it to a file:

js
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.

Dispatchers: Connection reuse and pooling

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 origins

Agent 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:

js
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:

js
await fetch('https://api.example.com/data', { dispatcher: agent })

Pool — for requests to a single origin

Pool manages a fixed set of connections to one origin. It gives you explicit control over concurrency:

js
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 connection

Client maps to a single TCP connection. It supports pipelining (sending multiple requests before responses arrive):

js
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:

Timeouts

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:

js
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.

Error handling

undici exposes structured errors via error.code:

js
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)
  }
}

Aborting requests

js
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
}

Common patterns

Proxies

Use ProxyAgent for HTTP(S) proxies, or EnvHttpProxyAgent to pick up proxy settings from environment variables:

js
import { ProxyAgent, setGlobalDispatcher } from 'undici'

const proxy = new ProxyAgent('http://proxy.internal:8080')
setGlobalDispatcher(proxy)

See Best Practices: Proxy and API Reference: ProxyAgent.

Mocking in tests

js
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.

Testing with undici

For test suites, set short keep-alive timeouts to avoid slow teardowns:

js
import { Agent, setGlobalDispatcher } from 'undici'

const agent = new Agent({
  keepAliveTimeout: 10,
  keepAliveMaxTimeout: 10
})
setGlobalDispatcher(agent)

See Best Practices: Writing Tests.

Customizing the global fetch

You can override Node.js's built-in globals with install():

js
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.

Further reading