Skip to main content

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

Undici ships a complete implementation of the WHATWG Fetch Standard. It is fully compatible with the browser fetch API: the same Request, Response, Headers, and FormData classes are used, and the same body mixin methods are available on both request and response objects.
Node.js has its own built-in fetch backed by a different dispatcher symbol. Keep fetch and FormData from the same implementation — either both from undici, both from Node.js globals, or install undici’s globals with install(). Mixing them produces unexpected multipart behavior.

undici.fetch(input, init)

Initiates an HTTP request following the Fetch standard. Returns a Promise<Response> that resolves when response headers are received. The response body is a Web ReadableStream and must be consumed.
import { fetch } from 'undici'

const response = await fetch('https://api.example.com/data')
const data = await response.json()

Parameters

input
string | URL | Request
required
The resource to fetch. Accepts a URL string, a WHATWG URL object, or a Request object. When a Request is passed, the init options are merged on top of it.Relative URLs are resolved against the global origin set by setGlobalOrigin(). A relative URL without a global origin set throws a TypeError.
init
object
Optional request configuration.

Return value

Returns Promise<Response>. See the Response class section for the full property and method reference.

Accepted body types

The body field of RequestInit and the Response constructor accept the following types:
TypeNotes
stringEncoded as UTF-8
ArrayBufferSent as raw bytes
ArrayBufferView (e.g. Uint8Array)Sent as raw bytes
BlobContent-Type set from blob.type if not already set
FormDataEncoded as multipart/form-data
URLSearchParamsEncoded as application/x-www-form-urlencoded
ReadableStreamStreaming — requires duplex: 'half'
AsyncIterable<Uint8Array>Streaming — requires duplex: 'half'

Streaming request bodies

To stream a request body using a ReadableStream or AsyncIterable, you must set duplex: 'half' in RequestInit. Without this field, the stream is not accepted.
Streaming request body
import { fetch } from 'undici'
import { Readable } from 'node:stream'

async function* generateData () {
  yield Buffer.from('chunk one\n')
  yield Buffer.from('chunk two\n')
}

const response = await fetch('https://upload.example.com', {
  method: 'POST',
  body: Readable.toWeb(Readable.from(generateData())),
  duplex: 'half',
  headers: { 'content-type': 'text/plain' }
})

await response.body.cancel() // consume or cancel the response body

Deviations from the spec

Undici’s fetch implementation follows the standard closely but differs in a few ways relevant to server-side use:
  • No CORS enforcement. CORS is a browser security mechanism. Undici does not reject cross-origin requests or strip response headers based on CORS rules.
  • Forbidden header handling. Some headers that browsers forbid (e.g. host) can be set or are not removed.
  • Content-Encoding limit. At most 5 layers of Content-Encoding are decoded. Responses with more layers result in an error.
  • formData() on the server. Parsing multipart/form-data with .formData() works but is not recommended for performance-critical paths. Prefer Busboy or @fastify/busboy instead.

Request

Represents an HTTP request. Implements the body mixin and all standard Request properties.
Constructing a Request
import { fetch, Request } from 'undici'

const req = new Request('https://api.example.com/users', {
  method: 'POST',
  headers: { 'content-type': 'application/json' },
  body: JSON.stringify({ name: 'Alice' })
})

const response = await fetch(req)

Constructor

new Request(input: string | URL | Request, init?: RequestInit)

Properties

url
string
The serialized URL of the request.
method
string
The HTTP method, e.g. 'GET', 'POST'.
headers
Headers
A Headers object containing the request headers.
body
ReadableStream | null
The request body as a Web ReadableStream, or null if none.
bodyUsed
boolean
true after the body has been consumed.
signal
AbortSignal
The abort signal associated with this request.
duplex
string
The duplex mode. 'half' when streaming bodies are used.
mode
string
The fetch mode ('cors', 'no-cors', etc.).
credentials
string
The credentials mode ('omit', 'same-origin', 'include').
cache
string
The cache mode.
redirect
string
The redirect mode ('follow', 'error', 'manual').
referrer
string
The referrer URL string.
referrerPolicy
string
The referrer policy.
integrity
string
Subresource Integrity string.
keepalive
boolean
Whether to keep the connection alive after the page unloads (browser context).

Methods

clone()
Request
Returns a copy of the Request. Throws if the body has already been consumed.

Response

Represents an HTTP response. Implements the body mixin and all standard Response properties.
Reading a Response
import { fetch } from 'undici'

const response = await fetch('https://api.example.com/users/1')

if (!response.ok) {
  console.error('HTTP error', response.status)
  await response.body.cancel()
} else {
  const user = await response.json()
  console.log(user)
}

Properties

status
number
HTTP status code (e.g. 200, 404).
statusText
string
HTTP status message (e.g. 'OK', 'Not Found').
ok
boolean
true when status is in the range 200299.
headers
Headers
Response headers as a Headers object.
url
string
The final URL after any redirects.
redirected
boolean
true if the response is the result of one or more redirects.
type
string
Response type: 'basic', 'cors', 'default', 'error', 'opaque', or 'opaqueredirect'.
body
ReadableStream | null
The response body as a Web ReadableStream. Convert to a Node.js stream with Readable.fromWeb(response.body).
bodyUsed
boolean
true after the body has been consumed.

Body methods

All body methods return a Promise and consume body exactly once.
json()
Promise<unknown>
Parses the body as JSON.
text()
Promise<string>
Reads the body as a UTF-8 string.
arrayBuffer()
Promise<ArrayBuffer>
Reads the body into an ArrayBuffer.
blob()
Promise<Blob>
Wraps the body in a Blob.
bytes()
Promise<Uint8Array>
Returns the body as a Uint8Array.
formData()
Promise<FormData>
Parses the body as multipart/form-data or application/x-www-form-urlencoded. Not recommended for server-side multipart parsing — use Busboy instead.

Static methods

Response.error()
Response
Returns a network error response.
Response.redirect(url, status?)
Response
Creates a redirect response. status must be one of 301, 302, 303, 307, or 308.
Response.json(data, init?)
Response
Creates a Response with a JSON-serialized body and content-type: application/json.

Methods

clone()
Response
Returns a copy of the Response. Throws if the body has already been consumed.

Converting the response body to a Node.js stream

The response body is a Web ReadableStream. To pipe it through Node.js stream APIs, convert it with Readable.fromWeb:
Converting body to a Node.js Readable
import { fetch } from 'undici'
import { Readable } from 'node:stream'
import { createWriteStream } from 'node:fs'

const response = await fetch('https://example.com/file.bin')
const nodeStream = Readable.fromWeb(response.body)
nodeStream.pipe(createWriteStream('./file.bin'))

Headers

Implements the WHATWG Headers interface. Used by both Request and Response.
Using Headers
import { Headers } from 'undici'

const headers = new Headers({
  'content-type': 'application/json',
  'x-api-key': 'secret'
})

headers.set('accept', 'application/json')
console.log(headers.get('content-type')) // 'application/json'
console.log(headers.has('x-api-key'))    // true
headers.delete('x-api-key')

Constructor

new Headers(init?: [string, string][] | Record<string, string> | Headers)

Methods

get(name)
string | null
Returns the value of the header, or null if not set. Multiple values are joined with ', '.
set(name, value)
void
Sets the header, replacing any existing value.
append(name, value)
void
Appends a value without replacing existing values for the same name.
has(name)
boolean
Returns true if the header exists.
delete(name)
void
Removes the header.
Returns all set-cookie header values as an array (one per value, unlike get() which joins them).
entries()
SpecIterableIterator<[string, string]>
Returns an iterator of [name, value] pairs.
keys()
SpecIterableIterator<string>
Returns an iterator of header names.
values()
SpecIterableIterator<string>
Returns an iterator of header values.
forEach(callback, thisArg?)
void
Calls callback(value, name, headers) for each header.

FormData

Implements the WHATWG FormData interface for building multipart/form-data request bodies.
Always pair FormData with fetch from the same implementation. Mixing undici’s FormData with Node.js built-in fetch (or vice versa) causes multipart encoding mismatches.
Submitting a form
import { fetch, FormData } from 'undici'

const form = new FormData()
form.append('username', 'alice')
form.append('avatar', new Blob(['...'], { type: 'image/png' }), 'avatar.png')

const response = await fetch('https://example.com/profile', {
  method: 'POST',
  body: form
})

Constructor

new FormData()
Passing any argument other than undefined throws an error.

Methods

append(name, value, filename?)
void
Appends a field. value may be a string or Blob. filename applies only when value is a Blob.
set(name, value, filename?)
void
Sets a field, replacing any existing entries with the same name.
get(name)
FormDataEntryValue | null
Returns the first value for name, or null.
getAll(name)
FormDataEntryValue[]
Returns all values for name.
has(name)
boolean
Returns true if a field with name exists.
delete(name)
void
Removes all entries with name.
entries()
IterableIterator<[string, FormDataEntryValue]>
Returns an iterator of [name, value] pairs.
keys()
IterableIterator<string>
Returns an iterator of field names.
values()
IterableIterator<FormDataEntryValue>
Returns an iterator of field values.
forEach(callback)
void
Calls callback(value, name, formData) for each entry.

Parsing multipart responses

For server-side multipart parsing, use Busboy or @fastify/busboy:
Parsing multipart with Busboy
import { Busboy } from '@fastify/busboy'
import { Readable } from 'node:stream'
import { fetch } from 'undici'

const response = await fetch('https://example.com/multipart-endpoint')
const busboy = new Busboy({
  headers: { 'content-type': response.headers.get('content-type') }
})

busboy.on('file', (field, stream, filename) => {
  console.log(`Receiving file: ${filename}`)
  stream.resume()
})

Readable.fromWeb(response.body).pipe(busboy)

Build docs developers (and LLMs) love