DNS

Use Bun's DNS module to resolve DNS records

Bun implements its own dns module and the node:dns module.

import * as dns from "node:dns";

const addrs = await dns.promises.resolve4("bun.com", { ttl: true });
console.log(addrs);
// => [{ address: "172.67.161.226", ttl: 0 }, ...]
import { dns } from "bun";

dns.prefetch("bun.com", 443);

Choosing a resolver backend#

Bun.dns.lookup() accepts a backend option that selects the resolver implementation:

  • "c-ares": the c-ares asynchronous resolver. It reads /etc/resolv.conf directly, so it does not consult NSS modules such as systemd-resolved. This backend is the default for Bun.dns.lookup() on Linux.
  • "system": the platform's own resolver (the non-blocking system API on macOS, getaddrinfo on a thread pool everywhere else). This backend is the default on macOS, Windows, and Android.
  • "getaddrinfo" (alias "libc"): the POSIX getaddrinfo(3) function on a thread pool.
import { dns } from "bun";

const [{ address }] = await dns.lookup("example.com", { backend: "system" });

node:dns.lookup() always uses the "system" backend to match Node.js, whose dns.lookup() is documented as calling getaddrinfo(3). The node:dns.resolve*() functions use c-ares, as they do in Node.js.

DNS caching in Bun#

Bun caches DNS lookups, which makes repeated connections to the same hosts faster.

The cache holds up to 256 entries for a maximum of 30 seconds each. If a connection to a host fails, Bun removes that host's entry from the cache. Simultaneous connections to the same host share one DNS lookup.

Bun uses this cache automatically in:

  • bun install
  • fetch()
  • node:http (client)
  • Bun.connect
  • node:net
  • node:tls

When should I prefetch a DNS entry?#

Web browsers expose <link rel="dns-prefetch"> to resolve a hostname before it's needed. In Bun, dns.prefetch does the same thing: use it when you know you'll connect to a host soon and want to avoid the initial DNS lookup.

import { dns } from "bun";

dns.prefetch("my.database-host.com", 5432);

A database driver is a good example: prefetch the database host's DNS entry when your application starts. By the time the rest of the application has loaded, the lookup may already be complete.

dns.prefetch#

This API is experimental and may change in the future.

dns.prefetch resolves a hostname before you need it.

dns.prefetch(hostname: string, port?: number): void;

Here's an example:

import { dns } from "bun";

dns.prefetch("bun.com", 443);
//
// ... sometime later ...
await fetch("https://bun.com");

dns.getCacheStats()#

This API is experimental and may change in the future.

dns.getCacheStats() returns the current cache stats as an object with the following properties:

{
  cacheHitsCompleted: number; // Cache hits completed
  cacheHitsInflight: number; // Cache hits in flight
  cacheMisses: number; // Cache misses
  size: number; // Number of items in the DNS cache
  errors: number; // Number of times a connection failed
  totalCount: number; // Number of times a connection was requested at all (including cache hits and misses)
}

Example:

import { dns } from "bun";

const stats = dns.getCacheStats();
console.log(stats);
// => { cacheHitsCompleted: 0, cacheHitsInflight: 0, cacheMisses: 0, size: 0, errors: 0, totalCount: 0 }

Configuring DNS cache TTL#

Bun caches DNS entries for 30 seconds by default. To change the TTL, set the $BUN_CONFIG_DNS_TIME_TO_LIVE_SECONDS environment variable. For example, to set it to 5 seconds:

BUN_CONFIG_DNS_TIME_TO_LIVE_SECONDS=5 bun run my-script.ts

Why is 30 seconds the default?#

The system API underneath (getaddrinfo) does not expose the TTL of a DNS entry, so Bun has to pick a number. We chose 30 seconds because it's long enough to see the benefits of caching and short enough to be unlikely to cause issues if a DNS entry changes. Amazon Web Services recommends 5 seconds for the Java Virtual Machine, though the JVM's default is to cache indefinitely.