Back to Blog
Node.jsDNSNetworkingSystem

Node.js DNS Module Guide

Master the Node.js dns module. From lookups to resolving records to custom DNS servers.

B
Bootspring Team
Engineering
June 6, 2020
7 min read

The dns module provides DNS resolution and lookup capabilities. Here's how to use it effectively.

Basic Lookups#

1const dns = require('dns'); 2const { promisify } = require('util'); 3 4// Callback-based lookup 5dns.lookup('google.com', (err, address, family) => { 6 if (err) { 7 console.error(err); 8 return; 9 } 10 console.log(`Address: ${address}, Family: IPv${family}`); 11}); 12 13// Promise-based lookup 14const lookupAsync = promisify(dns.lookup); 15 16async function lookup(hostname) { 17 try { 18 const { address, family } = await lookupAsync(hostname); 19 console.log(`Address: ${address}, Family: IPv${family}`); 20 return address; 21 } catch (err) { 22 console.error(`Lookup failed: ${err.message}`); 23 throw err; 24 } 25} 26 27// Using dns.promises (Node.js 10.6+) 28const dnsPromises = require('dns').promises; 29 30async function lookupModern(hostname) { 31 const result = await dnsPromises.lookup(hostname); 32 return result.address; 33}

IP Version Options#

1const dns = require('dns').promises; 2 3// Get IPv4 address 4async function getIPv4(hostname) { 5 const { address } = await dns.lookup(hostname, { family: 4 }); 6 return address; 7} 8 9// Get IPv6 address 10async function getIPv6(hostname) { 11 const { address } = await dns.lookup(hostname, { family: 6 }); 12 return address; 13} 14 15// Get all addresses 16async function getAllAddresses(hostname) { 17 const addresses = await dns.lookup(hostname, { all: true }); 18 return addresses; 19 // [{ address: '172.217.14.110', family: 4 }, ...] 20} 21 22// With hints 23async function lookupWithHints(hostname) { 24 const { address } = await dns.lookup(hostname, { 25 hints: dns.ADDRCONFIG | dns.V4MAPPED, 26 }); 27 return address; 28}

DNS Resolution#

1const dns = require('dns').promises; 2 3// Resolve A records (IPv4) 4async function resolveA(hostname) { 5 const addresses = await dns.resolve4(hostname); 6 return addresses; // ['172.217.14.110', ...] 7} 8 9// Resolve AAAA records (IPv6) 10async function resolveAAAA(hostname) { 11 const addresses = await dns.resolve6(hostname); 12 return addresses; 13} 14 15// Resolve MX records (mail) 16async function resolveMX(hostname) { 17 const records = await dns.resolveMx(hostname); 18 return records; 19 // [{ priority: 10, exchange: 'mail.example.com' }, ...] 20} 21 22// Resolve TXT records 23async function resolveTXT(hostname) { 24 const records = await dns.resolveTxt(hostname); 25 return records; 26 // [['v=spf1 include:_spf.google.com ~all'], ...] 27} 28 29// Resolve CNAME records 30async function resolveCNAME(hostname) { 31 const records = await dns.resolveCname(hostname); 32 return records; // ['www.example.com'] 33} 34 35// Resolve NS records (name servers) 36async function resolveNS(hostname) { 37 const records = await dns.resolveNs(hostname); 38 return records; // ['ns1.example.com', 'ns2.example.com'] 39} 40 41// Resolve SOA record (Start of Authority) 42async function resolveSOA(hostname) { 43 const record = await dns.resolveSoa(hostname); 44 return record; 45 // { nsname, hostmaster, serial, refresh, retry, expire, minttl } 46} 47 48// Resolve SRV records 49async function resolveSRV(hostname) { 50 const records = await dns.resolveSrv(hostname); 51 return records; 52 // [{ priority, weight, port, name }, ...] 53}

Generic Resolution#

1const dns = require('dns').promises; 2 3// Resolve any record type 4async function resolveAny(hostname) { 5 const records = await dns.resolveAny(hostname); 6 return records; 7 // Mixed array of all record types 8} 9 10// Resolve specific type 11async function resolve(hostname, recordType) { 12 const records = await dns.resolve(hostname, recordType); 13 return records; 14} 15 16// Usage 17await resolve('example.com', 'A'); 18await resolve('example.com', 'MX'); 19await resolve('example.com', 'TXT'); 20 21// Available record types: 22// 'A', 'AAAA', 'ANY', 'CAA', 'CNAME', 'MX', 'NAPTR', 23// 'NS', 'PTR', 'SOA', 'SRV', 'TXT'

Reverse DNS Lookup#

1const dns = require('dns').promises; 2 3// IP to hostname 4async function reverseLookup(ip) { 5 try { 6 const hostnames = await dns.reverse(ip); 7 return hostnames; // ['hostname.example.com'] 8 } catch (err) { 9 if (err.code === 'ENOTFOUND') { 10 return null; // No reverse DNS entry 11 } 12 throw err; 13 } 14} 15 16// Get PTR records 17async function resolvePTR(ip) { 18 const records = await dns.resolvePtr(ip); 19 return records; 20}

Custom DNS Servers#

1const dns = require('dns'); 2const { Resolver } = dns; 3 4// Create resolver with custom servers 5const resolver = new Resolver(); 6resolver.setServers(['8.8.8.8', '8.8.4.4']); // Google DNS 7 8// Use custom resolver 9resolver.resolve4('example.com', (err, addresses) => { 10 console.log(addresses); 11}); 12 13// Promise-based custom resolver 14const { promisify } = require('util'); 15const resolve4Async = promisify(resolver.resolve4.bind(resolver)); 16 17async function resolveWithGoogle(hostname) { 18 return resolve4Async(hostname); 19} 20 21// Get current DNS servers 22console.log(dns.getServers()); 23// ['192.168.1.1', '8.8.8.8'] 24 25// Set default servers 26dns.setServers(['1.1.1.1', '1.0.0.1']); // Cloudflare DNS

Error Handling#

1const dns = require('dns').promises; 2 3async function safeLookup(hostname) { 4 try { 5 const result = await dns.lookup(hostname); 6 return { success: true, ...result }; 7 } catch (err) { 8 return { 9 success: false, 10 code: err.code, 11 message: getErrorMessage(err.code), 12 }; 13 } 14} 15 16function getErrorMessage(code) { 17 const messages = { 18 ENODATA: 'DNS server returned answer with no data', 19 EFORMERR: 'DNS server claims query was misformatted', 20 ESERVFAIL: 'DNS server returned general failure', 21 ENOTFOUND: 'Domain name not found', 22 ENOTIMP: 'DNS server does not implement requested operation', 23 EREFUSED: 'DNS server refused query', 24 EBADQUERY: 'Misformatted DNS query', 25 EBADNAME: 'Misformatted hostname', 26 EBADFAMILY: 'Unsupported address family', 27 EBADRESP: 'Misformatted DNS reply', 28 ECONNREFUSED: 'Could not contact DNS servers', 29 ETIMEOUT: 'Timeout while contacting DNS servers', 30 EOF: 'End of file', 31 EFILE: 'Error reading file', 32 ENOMEM: 'Out of memory', 33 EDESTRUCTION: 'Channel is being destroyed', 34 EBADSTR: 'Misformatted string', 35 EBADFLAGS: 'Illegal flags specified', 36 ENONAME: 'Given hostname is not numeric', 37 EBADHINTS: 'Illegal hints flags specified', 38 ENOTINITIALIZED: 'c-ares library initialization not yet performed', 39 ELOADIPHLPAPI: 'Error loading iphlpapi.dll', 40 EADDRGETNETWORKPARAMS: 'Could not find GetNetworkParams function', 41 ECANCELLED: 'DNS query cancelled', 42 }; 43 return messages[code] || 'Unknown DNS error'; 44}

Caching DNS Results#

1const dns = require('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 return cached.result; 15 } 16 17 const result = await dns.lookup(hostname, options); 18 this.cache.set(key, { 19 result, 20 expires: Date.now() + this.ttl, 21 }); 22 23 return result; 24 } 25 26 async resolve(hostname, recordType = 'A') { 27 const key = `${hostname}:${recordType}`; 28 const cached = this.cache.get(key); 29 30 if (cached && Date.now() < cached.expires) { 31 return cached.result; 32 } 33 34 const result = await dns.resolve(hostname, recordType); 35 this.cache.set(key, { 36 result, 37 expires: Date.now() + this.ttl, 38 }); 39 40 return result; 41 } 42 43 clear() { 44 this.cache.clear(); 45 } 46} 47 48// Usage 49const dnsCache = new DNSCache(300000); // 5 minute TTL 50 51async function lookupCached(hostname) { 52 return dnsCache.lookup(hostname); 53}

Practical Examples#

1const dns = require('dns').promises; 2 3// Validate email domain 4async function validateEmailDomain(email) { 5 const domain = email.split('@')[1]; 6 if (!domain) return false; 7 8 try { 9 const mxRecords = await dns.resolveMx(domain); 10 return mxRecords.length > 0; 11 } catch { 12 return false; 13 } 14} 15 16// Check domain availability 17async function isDomainAvailable(domain) { 18 try { 19 await dns.lookup(domain); 20 return false; // Domain resolves, not available 21 } catch (err) { 22 if (err.code === 'ENOTFOUND') { 23 return true; // Domain doesn't resolve, might be available 24 } 25 throw err; 26 } 27} 28 29// Get all DNS info for domain 30async function getDomainInfo(domain) { 31 const info = { 32 domain, 33 addresses: [], 34 mx: [], 35 ns: [], 36 txt: [], 37 soa: null, 38 }; 39 40 try { 41 info.addresses = await dns.resolve4(domain); 42 } catch {} 43 44 try { 45 info.mx = await dns.resolveMx(domain); 46 } catch {} 47 48 try { 49 info.ns = await dns.resolveNs(domain); 50 } catch {} 51 52 try { 53 info.txt = await dns.resolveTxt(domain); 54 } catch {} 55 56 try { 57 info.soa = await dns.resolveSoa(domain); 58 } catch {} 59 60 return info; 61} 62 63// Health check with DNS 64async function checkDNSHealth(servers) { 65 const results = await Promise.all( 66 servers.map(async (server) => { 67 const resolver = new dns.Resolver(); 68 resolver.setServers([server]); 69 70 const start = Date.now(); 71 try { 72 await resolver.resolve4('google.com'); 73 return { 74 server, 75 status: 'healthy', 76 latency: Date.now() - start, 77 }; 78 } catch (err) { 79 return { 80 server, 81 status: 'unhealthy', 82 error: err.message, 83 }; 84 } 85 }) 86 ); 87 88 return results; 89}

Best Practices#

Usage: ✓ Use dns.promises for async/await ✓ Handle all error codes appropriately ✓ Implement caching for repeated lookups ✓ Use custom resolvers when needed Performance: ✓ Cache DNS results with appropriate TTL ✓ Use parallel resolution when possible ✓ Consider using faster DNS servers ✓ Implement timeouts Security: ✓ Validate hostnames before lookup ✓ Use DNSSEC when available ✓ Be aware of DNS rebinding attacks ✓ Log suspicious DNS queries Avoid: ✗ Blocking the event loop with sync calls ✗ Ignoring DNS errors ✗ Hardcoding DNS servers in production ✗ Making DNS calls in hot paths

Conclusion#

The dns module provides comprehensive DNS functionality for Node.js. Use dns.promises for modern async/await code, implement caching for performance, and handle errors appropriately. Consider using custom resolvers for specialized DNS requirements.

Share this article

Help spread the word about Bootspring