Engineering Atlas › System Design Fundamentals

How DNS turns names into addresses

14 min read · last reviewed 2026-10-17

Open in the interactive app: practice, quiz, mock interview →

In one minute

How it works

Delegation: who is authoritative

A zone is a slice of the name tree run by one operator. The parent holds NS records naming the child's nameservers, plus glue addresses when those nameservers live inside the child zone. The child holds its own NS, SOA and data. The registrar only puts your NS records into the TLD zone. If the parent points at a server that no longer serves the zone (a lame delegation), resolvers waste timeouts on it, and changing providers means changing parent NS records that com publishes with a two-day TTL.

What a resolver caches

A recursive resolver (Unbound, BIND, a cloud resolver, 1.1.1.1) caches four kinds of state, each with its own TTL:

Record types that shape designs

CNAME hands a hostname to a CDN or load balancer, but cannot sit at the zone apex next to SOA and NS; providers work around that with ALIAS records or "CNAME flattening". TXT carries ownership proofs (ACME DNS-01, SPF), CAA lists which CAs may issue for the domain, SRV gives host, port and weight for service discovery, and HTTPS records advertise protocols such as h3 before the first connection (RFC 9460).

TTL strategy

TTLs are a trade between agility and cost. Sensible defaults: NS and delegations at one to two days, stable A records at 5 to 60 minutes, records you may fail over at 30 to 60 seconds, and a negative TTL of a few minutes. Planned changes follow a pattern: lower the TTL to 60 seconds at least one old TTL before the change, make the change, verify, then raise it again. Lowering the TTL at the moment of the change does nothing for answers already cached under the old one.

Steering and failover

The authoritative server can answer per query by resolver location (GeoDNS), by the EDNS Client Subnet, by weight, or by health checks that remove dead endpoints. It sees the resolver's address, not the user's, and caching sets the limits (Google SRE book, ch. 19): one resolver fronts many users, some resolvers enforce minimum TTLs, client libraries cache on their own, and open connections never re-resolve. The DNS Load Balancing lesson covers the policies; remember that DNS failover takes minutes and its tail hours.

Resolvers inside your own fleet

Every process has a stub resolver (glibc's, configured by /etc/resolv.conf) that forwards to a recursive resolver. Its defaults matter at scale. Kubernetes sets ndots:5 and several search domains (Kubernetes DNS), so a lookup of api.stripe.com (two dots) first tries api.stripe.com.default.svc.cluster.local and two other suffixes, each for A and AAAA: eight queries instead of two. A node-local cache (NodeLocal DNSCache) or a trailing dot on external names (api.stripe.com.) removes most of that load.

Down the stack

Layer 1The contract

A resolver promises an answer that was true at the authority within the past TTL seconds, and carries no version, so stale looks exactly like current. NXDOMAIN is an authoritative "does not exist" and is cached; SERVFAIL means the resolver failed and is cached only briefly. With serve-stale (RFC 8767), a resolver that cannot reach any authority may return expired data, up to one to three days old, with a 30-second TTL. Nothing orders updates across names: a client may see one name's new record and another's old one.

Layer 2The mechanism

A referral is a response with an empty answer section, the child's NS records in the authority section and glue in the additional section, without the AA (authoritative answer) bit. The resolver algorithm (RFC 1034, section 5.3.3) is: look in the cache for the answer; otherwise find the closest ancestor zone whose delegation is cached, query one of its servers, and repeat on each referral until an authoritative answer or NXDOMAIN. Unbound keeps an infrastructure cache of each nameserver's smoothed round-trip time and prefers the fastest, and with prefetch: yes it refreshes popular entries when less than 10% of their TTL remains, so hot names never expire under load, at the cost of about 10% more upstream traffic (Unbound docs). QNAME minimisation (RFC 9156) sends each ancestor only the next label, so the root learns com, not your full hostname. DNSSEC adds RRSIG signatures over record sets, DNSKEY records for zone keys, and DS records in the parent that chain trust from the root.

Layer 3The machine

A query is one UDP datagram of 40 to 80 bytes; a cache hit in the same data centre returns in well under a millisecond, a cold recursive walk takes 50 to 200 ms. Answers too big for the size the client advertised in EDNS come back truncated (the TC bit set), and the client retries over TCP, which every general-purpose DNS implementation must support (RFC 7766). Since DNS Flag Day 2020 the recommended EDNS buffer is 1,232 bytes, the IPv6 minimum MTU minus headers, so answers never rely on IP fragmentation, which is unreliable and easier to spoof (DNS Flag Day 2020). Large DNSSEC answers therefore move to TCP more often than people expect, so firewalls must allow TCP port 53. The 16-bit query ID plus a randomised source port give about 32 bits an off-path attacker must guess to spoof an answer, the defence adopted after Kaminsky's 2008 attack. glibc's stub resolver waits 5 seconds before retrying a lost UDP query (resolv.conf(5)), so a single dropped packet shows up as a 5-second latency spike; in Kubernetes, a Linux conntrack race when A and AAAA queries leave the same socket in parallel produced exactly those spikes, which is one reason NodeLocal DNSCache skips DNAT and upgrades upstream queries to TCP (Kubernetes docs). The root's 13 server names are served by about 2,000 anycast instances (2,047 in October 2026, per root-servers.org), which is why a root outage has never taken down resolution.

Why it's built this way

  1. No single server can answer for every name, so authority is delegated down a tree.
  2. Walking the tree per lookup would be slow and melt its top, so answers, delegations and negatives are all cached.
  3. Caches cannot be told about changes, so TTL is the only consistency mechanism, and it is decided before the change.
  4. One small question and one small answer do not justify a connection, so DNS uses UDP, which caps message size (large answers fall back to TCP) and makes spoofing the main threat.
  5. Because so much rests on it, DNS favours availability over freshness: multiple nameservers, anycast, and serving stale data when authorities are unreachable.

Diagram

sequenceDiagram
  participant S as "Stub (app)"
  participant R as "Recursive resolver"
  participant Root as "Root server"
  participant T as "com server"
  participant A as "example.com server"
  S->>R: A www.example.com?
  Note over R: Cache miss, no delegation cached
  R->>Root: A www.example.com?
  Root-->>R: Referral: com NS + glue (TTL 2 days)
  R->>T: A www.example.com?
  T-->>R: Referral: example.com NS + glue (TTL 1 day)
  R->>A: A www.example.com?
  A-->>R: AA answer 192.0.2.1 (TTL 300)
  R-->>S: 192.0.2.1
  Note over R: Next query for example.com names goes straight to A

Worked example

You are moving api.example.com from an old load balancer to a new one. The record has a 1-hour TTL, and about 50,000 distinct resolvers query it.

Two hours before the change you drop the TTL to 60 seconds. Authoritative load rises from 50,000 / 3,600 = 14 to 50,000 / 60 = 830 queries per second, a few dollars a day at managed-provider prices. At cutover most resolvers move within 2 minutes. The tail is resolvers that clamp TTLs, JVM services that cache addresses for the life of the process, and pooled connections that stay on the old load balancer, so you keep it serving for 24 hours and watch its traffic fall to zero.

Now the fleet side: 3,000 pods each make 400 external lookups per second with ndots:5 and no node-local cache. Each lookup becomes 8 queries, so cluster DNS sees 3,000 x 400 x 8 = 9.6 million queries per second, mostly NXDOMAIN for search-path guesses. Trailing dots plus a node-local cache cut that by two to three orders of magnitude.

In the wild

Trade-offs

OptionStrengthsWeaknessesChoose when
Long TTL (1 hour to 1 day)Fewer queries, faster lookups, survives authority outages longerChanges and failover are slowStable records, NS and delegations
Short TTL (30 to 60 s)Fast changes and DNS failoverMore queries and more cold lookups on the critical pathRecords you may need to move during an incident
Single authoritative providerSimple, one API, one set of featuresProvider outage takes your names downSmall or internal zones
Two authoritative providersSurvives a provider outageMust keep zones in sync; proprietary features (geo, ALIAS) do not mixRevenue-critical public domains
GeoDNS steeringCheap, works with any IP addressesSteers resolvers, converges in minutesRegion selection
Anycast addressesRouting reacts in seconds, no client cacheNeeds BGP and owned address spaceEdge networks and DNS servers themselves
Node-local caching resolverCuts latency and central resolver loadOne more daemon per node to operateLarge Kubernetes or VM fleets

Pitfalls in production

Leadership lens

Check yourself

  1. You lowered a record's TTL from 1 day to 60 seconds and changed its address in the same edit. Why do some clients still see the old address the next morning?

    Show answer

    Resolvers that cached the old answer under the 1-day TTL keep it until that TTL expires. The lower TTL only affects answers fetched after the edit, so it must be lowered at least one old TTL in advance.

  2. Why does a warm recursive resolver almost never query a root server?

    Show answer

    It caches the delegations for TLDs such as com, which carry two-day TTLs, and starts each new lookup from the closest cached ancestor zone.

  3. What is the difference between NXDOMAIN and SERVFAIL for caching and retries?

    Show answer

    NXDOMAIN is an authoritative "does not exist" that resolvers cache for the negative TTL. SERVFAIL means the resolver failed to get an answer; it is cached only briefly and the client may retry or try another resolver.

  4. Why can a pod in Kubernetes send eight DNS queries to resolve api.stripe.com?

    Show answer

    With ndots:5, a name with fewer than five dots is first tried with each search domain appended, and each attempt asks for both A and AAAA.

Sources and further study

Primary

Systems docs

Books

Other curricula

Watch

Free resources

Open in the interactive app: practice, quiz, mock interview →