Skip to main content
Bun implements the WHATWG fetch standard with extensions tailored for server-side use. The fetch global is available everywhere without imports.

GET request

const response = await fetch("https://example.com");

console.log(response.status); // 200
console.log(response.headers.get("content-type")); // text/html; charset=UTF-8

const text = await response.text();

Common HTTP methods

const res = await fetch("https://api.example.com/users");
const users = await res.json();

Request headers

Pass headers as a plain object or a Headers instance:
const res = await fetch("https://api.example.com/data", {
  headers: {
    Authorization: "Bearer my-token",
    "Accept-Language": "en-US",
  },
});

Reading response bodies

MethodReturns
response.text()Promise<string>
response.json()Promise<any>
response.bytes()Promise<Uint8Array>
response.arrayBuffer()Promise<ArrayBuffer>
response.blob()Promise<Blob>
response.formData()Promise<FormData>
const res = await fetch("https://api.example.com/data");

// Read as JSON
const json = await res.json();

// Read as text
const text = await res.text();

// Write directly to a file
await Bun.write("output.json", res);

Streaming response bodies

Use response.body (a ReadableStream) or an async iterator to process large responses without buffering them entirely in memory:
const res = await fetch("https://example.com/large-file");

for await (const chunk of res.body) {
  process.stdout.write(chunk);
}

Streaming request bodies

Send a ReadableStream as a request body. Bun streams it directly to the network without buffering the entire body in memory:
const stream = new ReadableStream({
  start(controller) {
    controller.enqueue("Hello");
    controller.enqueue(", ");
    controller.enqueue("world!");
    controller.close();
  },
});

const res = await fetch("https://api.example.com/upload", {
  method: "POST",
  body: stream,
  headers: { "Content-Type": "text/plain" },
});

File uploads with FormData

const form = new FormData();
form.append("name", "Alice");
form.append("avatar", Bun.file("./avatar.png"), "avatar.png");

const res = await fetch("https://api.example.com/profile", {
  method: "POST",
  body: form,
  // Content-Type with multipart boundary is set automatically
});

Timeouts and cancellation

Timeout with AbortSignal.timeout()

try {
  const res = await fetch("https://slow.example.com", {
    signal: AbortSignal.timeout(5000), // abort after 5 seconds
  });
  const text = await res.text();
} catch (err) {
  if (err.name === "TimeoutError") {
    console.error("Request timed out");
  }
}

Manual cancellation with AbortController

const controller = new AbortController();

// Cancel after 3 seconds
setTimeout(() => controller.abort(), 3000);

const res = await fetch("https://api.example.com/stream", {
  signal: controller.signal,
});

Proxy support

Route requests through an HTTP or HTTPS proxy:
// Simple proxy
const res = await fetch("https://api.example.com/data", {
  proxy: "http://proxy.internal:8080",
});
Send custom headers to the proxy (for example, Proxy-Authorization):
const res = await fetch("https://api.example.com/data", {
  proxy: {
    url: "http://proxy.internal:8080",
    headers: {
      "Proxy-Authorization": "Bearer proxy-token",
    },
  },
});
You cannot use proxy and unix together in the same request.

Unix socket support

Fetch from a server listening on a Unix domain socket:
const res = await fetch("http://localhost/api/status", {
  unix: "/var/run/my-app.sock",
});
const data = await res.json();

TLS options

Use a client certificate for mutual TLS authentication:
const res = await fetch("https://secure.example.com", {
  tls: {
    key: Bun.file("/path/to/client.key"),
    cert: Bun.file("/path/to/client.crt"),
    ca: Bun.file("/path/to/ca.crt"),
  },
});
Disable certificate verification (development only):
const res = await fetch("https://self-signed.example.com", {
  tls: {
    rejectUnauthorized: false,
  },
});
Setting rejectUnauthorized: false disables TLS validation entirely. Never use this in production.
Custom server identity check:
const res = await fetch("https://example.com", {
  tls: {
    checkServerIdentity(hostname, cert) {
      if (hostname !== "expected.example.com") {
        return new Error("Hostname mismatch");
      }
    },
  },
});

Additional protocols

Beyond HTTP and HTTPS, Bun’s fetch supports several other URL schemes:
// Uses AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY / AWS_REGION env vars
const res = await fetch("s3://my-bucket/path/to/object");

// Or pass credentials explicitly
const res2 = await fetch("s3://my-bucket/path/to/object", {
  s3: {
    accessKeyId: "ACCESS_KEY",
    secretAccessKey: "SECRET_KEY",
    region: "us-east-1",
  },
});
const res = await fetch("file:///home/user/data.json");
const data = await res.json();
const res = await fetch("data:text/plain;base64,SGVsbG8sIFdvcmxkIQ==");
const text = await res.text(); // "Hello, World!"
const blob = new Blob(["Hello, World!"], { type: "text/plain" });
const url = URL.createObjectURL(blob);
const res = await fetch(url);

Performance

DNS prefetching

Warm up the DNS cache before you need to make a request:
import { dns } from "bun";

dns.prefetch("api.example.com");

// ... later, when the request is made, DNS is already resolved
const res = await fetch("https://api.example.com/data");

Preconnect

Start the TCP/TLS handshake before the request is issued:
import { fetch } from "bun";

fetch.preconnect("https://api.example.com");

// Or at startup via CLI
// bun --fetch-preconnect https://api.example.com server.ts

Connection pooling

Bun automatically pools and reuses connections to the same host (HTTP keep-alive). To opt out for a single request:
const res = await fetch("https://api.example.com", {
  keepalive: false,
});
The default maximum number of simultaneous connections is 256. Raise it with:
BUN_CONFIG_MAX_HTTP_REQUESTS=512 bun server.ts

Debugging

Set verbose: true to print request and response headers to the terminal:
const res = await fetch("https://example.com", {
  verbose: true,
});
[fetch] > HTTP/1.1 GET https://example.com/
[fetch] > Connection: keep-alive
[fetch] > User-Agent: Bun/1.3.3
[fetch] > Accept: */*
[fetch] > Host: example.com

[fetch] < 200 OK
[fetch] < Content-Type: text/html; charset=UTF-8
[fetch] < Content-Length: 648
Pass "curl" for more detailed output mimicking curl -v.

Build docs developers (and LLMs) love