How DNS resolution works under the hood: a step by step guide for high availability infrastructure

Binadit Tech Team 19 August 2026 8 min leggi
How DNS resolution works under the hood: a step by step guide for high availability infrastructure

What you will achieve

By the end of this guide you will understand exactly what happens between a user typing your domain and their browser opening a TCP connection to your server. You will also know how to configure DNS so it supports failover, low latency, and high availability infrastructure rather than becoming an unmonitored single point of failure.

DNS resolution is usually invisible. It only becomes visible when it adds 200ms to every request, when a failover does not happen because of a stale TTL, or when a misconfigured record sends traffic to a decommissioned server. Understanding the mechanism gives you control over all three.

Prerequisites and assumptions

This guide assumes:

  • You manage at least one domain through a DNS provider (Cloudflare, Route 53, or similar) with API or dashboard access.
  • You have shell access to a Linux machine with dig, nslookup, and tcpdump or ngrep available.
  • You understand basic networking concepts: IP addresses, TCP, and UDP.
  • You are working with a production domain, or a test domain where you can safely change records.

We will use example.com throughout. Replace it with your own domain when running commands.

Step by step: how resolution actually happens

Step 1: the browser checks its own cache

Before any network request happens, the browser checks its internal DNS cache. Chrome, for example, keeps a cache you can inspect directly:

chrome://net-internals/#dns

If a valid, non-expired record exists, resolution stops here. This is why changing a DNS record does not always take effect immediately in your own browser, even after the TTL has technically expired at the resolver level.

Step 2: the operating system resolver is checked

If the browser cache misses, the OS-level stub resolver is consulted. On Linux this is typically handled by systemd-resolved or nscd. You can inspect the local resolver cache and configuration with:

resolvectl statusnresolvectl statistics

The stub resolver checks /etc/hosts first, then its own cache, before forwarding the query.

Step 3: the recursive resolver takes over

If there is no local answer, the query goes to a recursive resolver, typically your ISP's resolver, or a public one like 1.1.1.1 or 8.8.8.8 if configured manually. You can query one directly to see the raw exchange:

dig @1.1.1.1 example.com +trace

The +trace flag is the most useful part of this whole guide. It shows every hop the resolver takes, which is exactly what we walk through next.

Step 4: root servers point to the TLD

The recursive resolver first asks one of the 13 root server clusters (labeled a-root through m-root) which servers are authoritative for the top-level domain, in this case .com. The root does not know where example.com lives. It only knows who manages .com.

; ANSWER: root servers respond with .com TLD nameserversncom. 172800 IN NS a.gtld-servers.net.ncom. 172800 IN NS b.gtld-servers.net.

Step 5: TLD servers point to your authoritative nameservers

The resolver then asks a .com TLD server the same question. This server responds with the authoritative nameservers configured for your domain, the ones you set at your registrar:

example.com. 172800 IN NS ns1.yourdnsprovider.com.nexample.com. 172800 IN NS ns2.yourdnsprovider.com.

Step 6: the authoritative nameserver returns the actual record

Finally, the resolver queries your authoritative nameserver directly and receives the actual A, AAAA, or CNAME record:

example.com. 300 IN A 203.0.113.42

This is the record you control. This is also the step where high availability infrastructure decisions actually matter: which IP is returned, how fast it changes, and what happens if that IP is unreachable.

Step 7: configuring records for high availability infrastructure

Once you understand the chain above, you can configure DNS to actively support failover rather than just point to a static IP. A few concrete patterns:

Low TTL for failover-critical records. A 3600 second TTL means a failover takes up to an hour to propagate to resolvers that already cached the old value. For records tied to failover logic, use 60 to 300 seconds:

example.com. 60 IN A 203.0.113.42

The tradeoff is more query volume against your authoritative nameservers, which is a reasonable cost for faster failover.

Health-checked DNS failover. Providers like Route 53 and Cloudflare support attaching health checks to records, so an unhealthy origin is automatically removed from the response set. Example Route 53 CLI snippet for a health-checked record:

aws route53 change-resource-record-sets \n  --hosted-zone-id Z1PA6795UKMFR9 \n  --change-batch '{n    "Changes": [{n      "Action": "UPSERT",n      "ResourceRecordSet": {n        "Name": "example.com",n        "Type": "A",n        "SetIdentifier": "primary",n        "Failover": "PRIMARY",n        "TTL": 60,n        "ResourceRecords": [{"Value": "203.0.113.42"}],n        "HealthCheckId": "abcd1234-healthcheck-id"n      }n    }]n  }'

This is the same mechanism we rely on during a zero-downtime migration, where DNS failover shifts traffic to a new environment without a hard cutover.

Multiple A records for redundancy. You can return more than one IP for a single record, and clients will fall back to the second if the first does not respond:

example.com. 300 IN A 203.0.113.42nexample.com. 300 IN A 203.0.113.43

This works well for stateless services behind a load balancer, but it is not a substitute for proper health-checked failover, since clients cache the order and do not always retry intelligently.

Verification: how to confirm it works

Do not assume your configuration is correct just because the dashboard looks right. Verify at each layer.

Check propagation and TTL behavior

dig example.com +noall +answerndig example.com @8.8.8.8 +noall +answerndig example.com @1.1.1.1 +noall +answer

Compare the TTL returned by each resolver. If you changed a record recently, TTLs lower than your configured value confirm the change is propagating; TTLs at the original value from a resolver mean it is still serving a cached answer.

Time the actual resolution

dig example.com | grep "Query time"

Anything above 100-150ms consistently suggests you should evaluate resolver placement or consider a DNS provider with more edge locations closer to your users. This directly affects time to first byte, since DNS resolution happens before the TCP handshake even starts.

Simulate a failover

If you have health-checked failover configured, test it deliberately rather than waiting for a real incident:

# Temporarily block health check traffic on the primary originniptables -A INPUT -s 

Then confirm the DNS response switches to the secondary record within your configured TTL:

watch -n 5 'dig example.com +short'

Remove the rule once verified. This kind of controlled test belongs in the same category as staging validation, which we cover in why staging environments mislead and how to build reliable testing.

Monitor resolution as an ongoing metric

Add DNS resolution time as its own metric in your monitoring stack, separate from full page load. A sudden spike in resolution time, even with backend response times unchanged, points to a resolver or authoritative nameserver problem rather than an application issue. This kind of separation is exactly what makes uptime percentages tell the full story instead of hiding DNS-layer degradation behind an average.

Common pitfalls to avoid

  • TTLs left at provider defaults. A default of 3600 or 86400 seconds quietly undermines any failover strategy you build on top of it.
  • Relying on a single authoritative nameserver provider. If that provider has an outage, your domain becomes unreachable regardless of how healthy your servers are.
  • Forgetting DNSSEC validation chains. If you enable DNSSEC, misconfigured signing can cause silent resolution failures for resolvers that enforce validation, while looking fine in tools that skip it.
  • Testing only from your own machine. Your local resolver cache will hide problems that real users experience. Always test against multiple public resolvers.
  • Ignoring CNAME chaining depth. Each additional CNAME hop adds a round trip. Two or three chained CNAMEs (common with some CDN and SaaS integrations) can add measurable latency.

Next steps and related reading

Once DNS resolution is verified and tuned, the next logical layer to review is what happens after the connection is established: TLS negotiation, server response time, and caching behavior. If you are running a migration that depends on DNS-based cutover, read our 6-phase zero-downtime migration playbook for how DNS fits into a broader cutover plan without downtime.

If DNS resolution time is part of a wider performance investigation, our guide on how to trace performance bottlenecks end to end walks through the rest of the request path, from TCP handshake through backend processing.

Bringing it together

DNS is a small piece of the request lifecycle, but it sits in front of everything else, and misconfigured TTLs or a single point of failure at the nameserver level can undermine an otherwise solid high availability infrastructure setup. Treat DNS configuration with the same rigor you apply to your application and database layer: verify it, monitor it, and test failover deliberately instead of assuming it works.

Need this running in production without building it yourself? See our managed infrastructure services or schedule a call.