The dns module provides DNS resolution and lookup capabilities. Here's how to use it for network operations.
Basic Lookup#
1import dns from 'node:dns';
2import { promisify } from 'node:util';
3
4const lookup = promisify(dns.lookup);
5
6// Simple lookup
7async function resolveHostname(hostname) {
8 try {
9 const result = await lookup(hostname);
10 console.log('Address:', result.address);
11 console.log('Family:', result.family); // 4 or 6
12 return result;
13 } catch (error) {
14 console.error('Lookup failed:', error.message);
15 throw error;
16 }
17}
18
19await resolveHostname('google.com');
20// Address: 142.250.80.46
21// Family: 4Promise-based API#
1import dns from 'node:dns/promises';
2
3// Use promises API directly
4async function dnsOperations() {
5 // Lookup
6 const address = await dns.lookup('example.com');
7 console.log('IP:', address.address);
8
9 // Resolve multiple record types
10 const mx = await dns.resolveMx('gmail.com');
11 console.log('MX records:', mx);
12
13 const txt = await dns.resolveTxt('google.com');
14 console.log('TXT records:', txt);
15}Lookup Options#
1import dns from 'node:dns/promises';
2
3// IPv4 only
4const ipv4 = await dns.lookup('google.com', { family: 4 });
5console.log('IPv4:', ipv4.address);
6
7// IPv6 only
8const ipv6 = await dns.lookup('google.com', { family: 6 });
9console.log('IPv6:', ipv6.address);
10
11// All addresses
12const all = await dns.lookup('google.com', { all: true });
13console.log('All addresses:', all);
14// [{ address: '...', family: 4 }, { address: '...', family: 6 }]
15
16// With hints
17const hints = await dns.lookup('google.com', {
18 hints: dns.ADDRCONFIG | dns.V4MAPPED,
19});Resolve DNS Records#
1import dns from 'node:dns/promises';
2
3// A records (IPv4)
4async function resolveA(hostname) {
5 const addresses = await dns.resolve4(hostname);
6 console.log('A records:', addresses);
7 return addresses;
8}
9
10// AAAA records (IPv6)
11async function resolveAAAA(hostname) {
12 const addresses = await dns.resolve6(hostname);
13 console.log('AAAA records:', addresses);
14 return addresses;
15}
16
17// MX records (mail)
18async function resolveMX(hostname) {
19 const records = await dns.resolveMx(hostname);
20 console.log('MX records:', records);
21 // [{ exchange: 'mail.example.com', priority: 10 }]
22 return records.sort((a, b) => a.priority - b.priority);
23}
24
25// TXT records
26async function resolveTXT(hostname) {
27 const records = await dns.resolveTxt(hostname);
28 console.log('TXT records:', records);
29 return records.flat();
30}
31
32// NS records (nameservers)
33async function resolveNS(hostname) {
34 const nameservers = await dns.resolveNs(hostname);
35 console.log('NS records:', nameservers);
36 return nameservers;
37}
38
39// CNAME records
40async function resolveCNAME(hostname) {
41 try {
42 const cname = await dns.resolveCname(hostname);
43 console.log('CNAME:', cname);
44 return cname;
45 } catch (error) {
46 if (error.code === 'ENODATA') {
47 return null; // No CNAME record
48 }
49 throw error;
50 }
51}SOA Records#
1import dns from 'node:dns/promises';
2
3async function getSOA(domain) {
4 const soa = await dns.resolveSoa(domain);
5 console.log('SOA Record:');
6 console.log(' Primary NS:', soa.nsname);
7 console.log(' Admin:', soa.hostmaster);
8 console.log(' Serial:', soa.serial);
9 console.log(' Refresh:', soa.refresh);
10 console.log(' Retry:', soa.retry);
11 console.log(' Expire:', soa.expire);
12 console.log(' Min TTL:', soa.minttl);
13 return soa;
14}
15
16await getSOA('google.com');SRV Records#
1import dns from 'node:dns/promises';
2
3async function resolveSRV(service) {
4 const records = await dns.resolveSrv(service);
5
6 // Sort by priority, then weight
7 records.sort((a, b) => {
8 if (a.priority !== b.priority) {
9 return a.priority - b.priority;
10 }
11 return b.weight - a.weight;
12 });
13
14 console.log('SRV records:');
15 records.forEach((r) => {
16 console.log(` ${r.name}:${r.port} (priority: ${r.priority}, weight: ${r.weight})`);
17 });
18
19 return records;
20}
21
22// Example: XMPP server discovery
23await resolveSRV('_xmpp-server._tcp.gmail.com');Reverse DNS Lookup#
1import dns from 'node:dns/promises';
2
3async function reverseLookup(ip) {
4 try {
5 const hostnames = await dns.reverse(ip);
6 console.log(`${ip} resolves to:`, hostnames);
7 return hostnames;
8 } catch (error) {
9 if (error.code === 'ENOTFOUND') {
10 console.log(`No PTR record for ${ip}`);
11 return [];
12 }
13 throw error;
14 }
15}
16
17await reverseLookup('8.8.8.8');
18// ['dns.google']Resolve Any Record Type#
1import dns from 'node:dns/promises';
2
3async function resolveAny(hostname) {
4 try {
5 const records = await dns.resolveAny(hostname);
6
7 records.forEach((record) => {
8 console.log(`${record.type}:`, record);
9 });
10
11 return records;
12 } catch (error) {
13 console.error('Failed to resolve:', error.message);
14 throw error;
15 }
16}
17
18// Get all available records
19await resolveAny('google.com');Custom DNS Servers#
1import dns from 'node:dns';
2import { Resolver } from 'node:dns/promises';
3
4// Create resolver with custom servers
5const resolver = new Resolver();
6resolver.setServers(['8.8.8.8', '8.8.4.4']); // Google DNS
7
8async function lookupWithCustomDNS(hostname) {
9 const addresses = await resolver.resolve4(hostname);
10 console.log('Using custom DNS:', addresses);
11 return addresses;
12}
13
14// Get current DNS servers
15console.log('Current servers:', dns.getServers());
16
17// Set servers globally (affects all lookups)
18dns.setServers(['1.1.1.1', '1.0.0.1']); // Cloudflare DNSDNS Cache#
1import dns from 'node:dns/promises';
2
3class DNSCache {
4 constructor(ttl = 60000) {
5 this.cache = new Map();
6 this.ttl = ttl;
7 }
8
9 async lookup(hostname, options = {}) {
10 const key = `${hostname}-${options.family || 'any'}`;
11 const cached = this.cache.get(key);
12
13 if (cached && Date.now() < cached.expires) {
14 console.log('Cache hit:', hostname);
15 return cached.result;
16 }
17
18 console.log('Cache miss:', hostname);
19 const result = await dns.lookup(hostname, options);
20
21 this.cache.set(key, {
22 result,
23 expires: Date.now() + this.ttl,
24 });
25
26 return result;
27 }
28
29 async resolve4(hostname) {
30 const key = `A-${hostname}`;
31 const cached = this.cache.get(key);
32
33 if (cached && Date.now() < cached.expires) {
34 return cached.result;
35 }
36
37 const result = await dns.resolve4(hostname);
38 this.cache.set(key, {
39 result,
40 expires: Date.now() + this.ttl,
41 });
42
43 return result;
44 }
45
46 clear() {
47 this.cache.clear();
48 }
49}
50
51const dnsCache = new DNSCache(300000); // 5 minute TTLHealth Check with DNS#
1import dns from 'node:dns/promises';
2
3async function checkDNSHealth(hostname, expectedIPs = []) {
4 const startTime = Date.now();
5
6 try {
7 const result = await dns.lookup(hostname, { all: true });
8 const duration = Date.now() - startTime;
9
10 const ips = result.map((r) => r.address);
11 const hasExpected = expectedIPs.every((ip) => ips.includes(ip));
12
13 return {
14 hostname,
15 healthy: true,
16 duration,
17 addresses: ips,
18 expectedMatch: hasExpected,
19 };
20 } catch (error) {
21 return {
22 hostname,
23 healthy: false,
24 duration: Date.now() - startTime,
25 error: error.message,
26 code: error.code,
27 };
28 }
29}
30
31async function monitorDNS(hostnames, interval = 30000) {
32 setInterval(async () => {
33 for (const hostname of hostnames) {
34 const health = await checkDNSHealth(hostname);
35 if (!health.healthy) {
36 console.error(`DNS health check failed for ${hostname}:`, health);
37 }
38 }
39 }, interval);
40}Error Handling#
1import dns from 'node:dns/promises';
2
3async function safeLookup(hostname) {
4 try {
5 return await dns.lookup(hostname);
6 } catch (error) {
7 switch (error.code) {
8 case 'ENOTFOUND':
9 console.error(`Hostname not found: ${hostname}`);
10 break;
11 case 'ENODATA':
12 console.error(`No data for: ${hostname}`);
13 break;
14 case 'ETIMEOUT':
15 console.error(`DNS timeout for: ${hostname}`);
16 break;
17 case 'ESERVFAIL':
18 console.error(`DNS server failure for: ${hostname}`);
19 break;
20 case 'ECONNREFUSED':
21 console.error(`DNS connection refused for: ${hostname}`);
22 break;
23 default:
24 console.error(`DNS error for ${hostname}:`, error.message);
25 }
26 throw error;
27 }
28}
29
30// With retry
31async function lookupWithRetry(hostname, retries = 3, delay = 1000) {
32 for (let i = 0; i < retries; i++) {
33 try {
34 return await dns.lookup(hostname);
35 } catch (error) {
36 if (i === retries - 1) throw error;
37 await new Promise((r) => setTimeout(r, delay));
38 }
39 }
40}Best Practices#
Lookup vs Resolve:
✓ lookup() uses OS resolver (cached)
✓ resolve() queries DNS directly
✓ Use lookup() for general use
✓ Use resolve() for specific records
Performance:
✓ Cache DNS results
✓ Use connection pooling
✓ Set reasonable timeouts
✓ Handle failures gracefully
Error Handling:
✓ Check error.code
✓ Implement retries
✓ Log DNS failures
✓ Have fallback servers
Avoid:
✗ Hardcoding IPs
✗ Ignoring TTLs
✗ Blocking on DNS
✗ No timeout handling
Conclusion#
The Node.js dns module provides comprehensive DNS resolution capabilities. Use lookup() for general hostname resolution with OS caching, and resolve*() methods for specific record types. Implement caching for performance, handle errors with retry logic, and use custom resolvers for specific DNS servers. The promises API makes async DNS operations clean and composable for modern Node.js applications.