How to fix Error: DNS timeout in Node.js
DNS timeout errors occur when Node.js cannot resolve a hostname within the expected timeframe, often due to network issues, slow DNS servers, or threadpool exhaustion. This guide shows how to configure timeouts and implement caching strategies.
Quick fix
Fixes Error: DNS timeout
# Test DNS resolution manually
nslookup example.com
dig example.com
# Check your DNS configuration
cat /etc/resolv.conf- Verify DNS server connectivity
- Implement DNS caching with a custom resolver
- Configure timeout for dns.resolve() methods
- Increase libuv threadpool size
# Test DNS resolution manuallynslookup example.comdig example.com# Check your DNS configurationcat /etc/resolv.confError: DNS timeout
What this error means
The "DNS timeout" error in Node.js indicates that a DNS lookup operation failed to complete within the allotted time. This happens when trying to resolve a hostname to an IP address, and the DNS server either doesn't respond or responds too slowly. Node.js uses two different methods for DNS resolution: `dns.lookup()` which uses the system's getaddrinfo(3) function and runs on libuv's threadpool, and `dns.resolve*()` which uses c-ares library and operates asynchronously. The timeout behavior differs between these methods. A critical aspect of this error is that Node.js's default thread pool has only 4 threads. When multiple slow DNS queries block these threads, it can cause a cascading failure affecting not just DNS lookups but also file I/O and crypto operations that share the same threadpool.
Typical symptoms
- Network requests fail with DNS timeout errors after prolonged waiting
- Application hangs when making HTTP requests to external services
- ETIMEDOUT errors appear in logs when resolving hostnames
- Subsequent DNS lookups queue up and fail even if individual servers are reachable
- File I/O and crypto operations slow down unexpectedly during DNS issues
Common causes
- DNS server is unreachable or responding slowly due to network congestion
- Firewall or network policy blocking DNS queries on port 53
- Too many concurrent DNS lookups exhausting Node.js's 4-thread libuv threadpool
- DNS server is overloaded or rate-limiting requests
- Incorrect DNS server configuration in /etc/resolv.conf or system settings
- IPv6 DNS queries timing out while IPv4 works (or vice versa)
- Container or Kubernetes environment with DNS caching issues
How to fix "Error: DNS timeout"
Test if your DNS servers are reachable from your environment:
# Test DNS resolution manually
nslookup example.com
dig example.com
# Check your DNS configuration
cat /etc/resolv.confIf these commands timeout, the issue is at the network/DNS level, not Node.js.
Use the dns.promises API with caching to avoid repeated lookups:
const dns = require('dns').promises;
const cache = new Map();
async function cachedLookup(hostname) {
const now = Date.now();
const cached = cache.get(hostname);
// Use cached result if still valid (60 second TTL)
if (cached && now - cached.timestamp < 60000) {
return cached.address;
}
const { address } = await dns.lookup(hostname);
cache.set(hostname, { address, timestamp: now });
return address;
}
// Usage
try {
const ip = await cachedLookup('example.com');
console.log('Resolved IP:', ip);
} catch (err) {
console.error('DNS lookup failed:', err);
}If using the c-ares based resolver, configure timeout settings:
const dns = require('dns');
const { Resolver } = dns;
const resolver = new Resolver();
// Set custom DNS servers
resolver.setServers(['8.8.8.8', '1.1.1.1']);
// Resolve with timeout handling
const timeoutPromise = new Promise((_, reject) =>
setTimeout(() => reject(new Error('DNS timeout')), 5000)
);
const resolvePromise = new Promise((resolve, reject) => {
resolver.resolve4('example.com', (err, addresses) => {
if (err) reject(err);
else resolve(addresses);
});
});
try {
const addresses = await Promise.race([resolvePromise, timeoutPromise]);
console.log('Resolved addresses:', addresses);
} catch (err) {
console.error('DNS resolution failed:', err.message);
}If you're using dns.lookup() and experiencing threadpool exhaustion, increase the pool size:
# Set before starting Node.js
export UV_THREADPOOL_SIZE=128
node app.jsOr programmatically (must be set before any async operations):
process.env.UV_THREADPOOL_SIZE = 128;
// Now start your application
const http = require('http');
// ... rest of your codeNote: This only affects dns.lookup(), not dns.resolve*().
Avoid threadpool blocking by using the c-ares based resolver:
const dns = require('dns').promises;
// Instead of dns.lookup() which blocks the threadpool
async function resolveHostname(hostname) {
try {
// Use resolve4/resolve6 which don't block threadpool
const addresses = await dns.resolve4(hostname);
return addresses[0]; // Return first IP
} catch (err) {
console.error('DNS resolution failed:', err.message);
throw err;
}
}
// Usage
resolveHostname('example.com')
.then(ip => console.log('Resolved IP:', ip))
.catch(err => console.error('Error:', err));Configure DNS resolver behavior via environment variables:
# Set retry and timeout parameters
export RES_OPTIONS='retrans:1000 retry:3 rotate'
node app.jsParameters:
- retrans: Timeout in milliseconds (default: 5000)
- retry: Number of retries (default: 4)
- rotate: Rotate through available DNS servers
For production environments, use a local DNS cache like dnsmasq:
# Install dnsmasq (Ubuntu/Debian)
sudo apt-get install dnsmasq
# Configure it to cache DNS queries
sudo systemctl start dnsmasq
sudo systemctl enable dnsmasq
# Point Node.js to use localhost DNS
# Edit /etc/resolv.conf
nameserver 127.0.0.1Or in Kubernetes, use NodeLocal DNSCache to cache DNS on each node.
Advanced notes
Thread Pool Considerations: Before Node.js v10.12.0, slow DNS queries could block ALL threadpool operations including file I/O and compression. Modern versions isolate DNS lookups better, but the 4-thread limit still applies.
HTTP Keep-Alive: Configure HTTP clients to reuse connections, reducing the number of DNS lookups needed:
const http = require('http');
const agent = new http.Agent({ keepAlive: true });
http.get({ hostname: 'example.com', agent }, (res) => {
// Connection will be reused
});DNS Prefetching: For known hostnames, pre-populate your DNS cache during application startup to avoid on-demand lookups that might timeout.
Kubernetes/Container Environments: DNS issues are particularly common in containerized environments. The NodeLocal DNSCache add-on can dramatically improve reliability by running a DNS cache on each worker node.
IPv6 Fallback: Some networks have broken IPv6 configurations. You can disable IPv6 DNS lookups by using dns.resolve4() explicitly instead of dns.resolve() which tries both IPv4 and IPv6.
Frequently asked questions
- What does "Error: DNS timeout" mean?
- js indicates that a DNS lookup operation failed to complete within the allotted time. This happens when trying to resolve a hostname to an IP address, and the DNS server either doesn't respond or responds too slowly. resolve*() which uses c-ares library and operates asynchronously.
- How do I fix "Error: DNS timeout"?
- DNS timeout errors occur when Node.js cannot resolve a hostname within the expected timeframe, often due to network issues, slow DNS servers, or threadpool exhaustion. This guide shows how to configure timeouts and implement caching strategies.
- What causes "Error: DNS timeout"?
- DNS server is unreachable or responding slowly due to network congestion Firewall or network policy blocking DNS queries on port 53 Too many concurrent DNS lookups exhausting Node.js's 4-thread libuv threadpool
- Is the "Error: DNS timeout" error serious?
- It is a medium-severity error โ more of a blocker than a risk. The steps above resolve it.
Official resources & further reading
- ๐Node.js Official Documentation
- ๐
- ๐
- ๐
- ๐
- ๐github.com - 7231(GitHub)