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.confdirectly, so it does not consult NSS modules such assystemd-resolved. This backend is the default forBun.dns.lookup()on Linux."system": the platform's own resolver (the non-blocking system API on macOS,getaddrinfoon a thread pool everywhere else). This backend is the default on macOS, Windows, and Android."getaddrinfo"(alias"libc"): the POSIXgetaddrinfo(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 installfetch()node:http(client)Bun.connectnode:netnode: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.