Design DNS — the walkthrough in full
A written version of the interactive walkthrough above — the same steps, decisions and trade-offs, laid out for reading, reference and search.
The big idea
What does DNS do?
Computers talk over IP addresses (142.250.72.14); humans remember names (google.com). Something has to translate names to addresses — billions of times a second, for every domain on Earth, with no central owner and no downtime. That's a deceptively hard distributed-systems problem.
DNS is the internet's phone book: give it a name, it returns an address. The trick is doing it at planetary scale. There's no single table — the namespace is split into a hierarchy that's delegated to independent owners, walked by resolvers, and made fast by aggressive caching.
How to read this: Each step opens with a real design decision — make the call before I show you what ships. Watch the tree grow, and at the end drop the cache and kill a nameserver to see why DNS almost never goes down. Hit Begin.
Step 1 · The naive table
One giant lookup table?
The simplest design: one central server holding a table of every name → IP mapping on the internet. Every device queries it. Why is that a non-starter?
Design decision: One central name→IP table for the whole internet. What breaks first?
The call: It can't take the load, it's a single point of failure, and no one entity can own all names. — One table means one bottleneck, one thing to DDoS into oblivion, and one owner deciding every domain on Earth. DNS solves all three by splitting and delegating the namespace.
Three fatal problems: load (no machine serves the whole internet's queries), availability (one table is one thing to kill), and control (no single entity should own every name). The answer to all three is the same: don't centralize the table — split and delegate it.
Why not centralize: Any design where the whole world depends on one component fails on scale, resilience and politics at once. DNS is a case study in solving all three with hierarchy + delegation + caching rather than a bigger box.
Step 2 · Someone to do the walking
The recursive resolver
If the answer isn't in one place, a client would have to chase it across many servers. You don't want every phone and laptop implementing that whole dance. Who does the legwork?
Design decision: If no single server has the answer, who does the multi-step lookup for the client?
The call: A recursive resolver: the client asks it once, it walks the hierarchy and returns the final answer. — The OS stub resolver hands the whole question to a recursive resolver (your ISP's, or 8.8.8.8). It does the root→TLD→authoritative walk and returns just the answer — and caches it to help the next user.
Introduce the recursive resolver (your ISP's, or a public one like 8.8.8.8). The client's tiny stub resolver asks it one question — "what's the IP for vibeengines.com?" — and the resolver does all the walking, returning just the final answer. It also caches, so it can answer the next person instantly.
Stub vs recursive: The stub resolver in your OS is dumb on purpose — it just forwards to a recursive resolver. The recursive resolver is the workhorse that walks the tree and caches results for all its users. Splitting "ask" from "resolve" is what keeps clients simple.
Step 3 · Split the namespace
A delegated hierarchy
The resolver needs to find the answer without any one server knowing everything. How do you organize billions of names so the lookup is a short, delegated walk instead of one impossible table?
Design decision: How is the name space organized so no server holds everything?
The call: A tree: root delegates to TLDs (.com), which delegate to the domain's authoritative server. — Read a name right-to-left: root knows who runs .com; the .com TLD knows who runs vibeengines.com; that authoritative nameserver holds the actual records. Each level owns and delegates its slice.
Organize names as a tree, read right-to-left, with each level delegating to the next. The root knows which servers run each TLD; the TLD servers (.com) know which authoritative nameserver owns vibeengines.com; that authoritative server holds the real records. No server knows everything — each just points one step down.
Delegation: www.vibeengines.com. → the trailing dot is the root. Root → ".com is over there." .com → "vibeengines.com's nameserver is over there." Authoritative → "here's the IP." Three delegations, and every zone is independently owned and operated.
Step 4 · The walk
Recursive resolution, step by step
Put it together: the resolver has a name and knows the tree exists. Trace exactly how it turns vibeengines.com into an IP starting from knowing nothing but the root.
The resolver walks down: ask a root server → it refers you to the .com TLD servers. Ask a TLD server → it refers you to vibeengines.com's authoritative nameserver. Ask the authoritative server → it returns the A record (the IP). Three referrals, one answer. The resolver hands it back to the client — and remembers it.
Referrals, not redirects: Each server the resolver asks either answers (authoritative) or refers ("I don't know, but ask these servers one level down"). The resolver follows referrals until it hits an authoritative answer. It always knows where to start because every resolver ships with the root hints — the addresses of the root servers.
Step 5 · Why it feels instant
Caching with TTL
A three-server walk for every single lookup would be slow, and would crush the root and TLD servers under the whole internet's traffic. Yet DNS feels instant. What makes it fast and spares the upstream servers?
Design decision: A full walk every lookup would be slow and crush the root/TLDs. What saves it?
The call: Resolvers cache answers for a TTL; most lookups never leave the resolver. — Each record carries a TTL set by its owner. The resolver caches the answer for that long, so the overwhelming majority of queries are served from cache and never touch root/TLD/authoritative servers at all.
Caching with a TTL. Every record carries a Time To Live set by its owner (e.g. 300s or a day). The resolver caches each answer for that long, so almost every lookup is served straight from the resolver's memory — never touching the hierarchy. Caching is what makes DNS fast and what keeps the root and TLD servers from being overwhelmed.
TTL is the trade dial: A long TTL means fewer upstream queries and faster answers, but changes take longer to spread. A short TTL means quick updates but more load and slower average lookups. The record owner picks the TTL to trade freshness against load — the same lever a CDN uses.
Step 6 · Never go dark
Replication & anycast
The root, the TLDs and each zone's authoritative server are now critical infrastructure. A single machine for any of them would be a global outage waiting to happen — and an irresistible DDoS target. How do you make them unkillable?
Design decision: The root/TLD/authoritative servers are critical. How do you make them survive failure and attack?
The call: Replicate every level and serve each address from many machines via anycast. — Every zone runs multiple authoritative servers; the 13 root "identities" are each anycast to hundreds of physical servers worldwide. Many machines share one address, so load spreads and a dead one is simply routed around.
Replicate everything and front it with anycast. Every zone must run multiple authoritative nameservers. The 13 root server identities are each anycast to hundreds of physical machines around the globe — one IP, served from the nearest healthy instance. Load spreads, latency drops, and a dead server (or a DDoS on one location) is just routed around.
Anycast for infrastructure: Anycast (one IP announced from many places, network delivers to the nearest) turns a would-be single point of failure into a self-healing swarm. It's why the root — a constant DDoS target — has never been globally downed: an attack hits one anycast instance, and traffic flows to the others.
Step 7 · Smarter answers
GeoDNS & traffic steering
DNS can do more than return a fixed IP. The same name can resolve to different addresses for different users — to send them to a nearby data center, balance load, or route around an unhealthy region. How?
On the authoritative side, add GeoDNS / traffic management: return a different IP based on the resolver's location (nearest data center), server health (skip a down region), or weight (split traffic for a canary). This makes DNS a coarse global load balancer and failover mechanism — the first hop of routing users to the right place (exactly what a CDN leans on).
DNS as a routing layer: Because the authoritative server chooses what to answer, it can steer: latency-based (nearest), geo (by country), weighted (A/B), or failover (health-checked). The catch is TTL — steering only re-routes as fast as caches expire, so failover TTLs are kept short.
Step 8 · The sharp edges
Propagation, negatives, security
Real DNS has famous gotchas: changes that "haven't propagated," repeated lookups of names that don't exist, DDoS amplification, and the fact that a plain DNS answer can be forged.
Propagation delay is just caching: a change is invisible until old TTLs expire, so you lower TTLs before a planned change. Negative caching remembers NXDOMAIN (name doesn't exist) so typos don't hammer the hierarchy. Defend against DDoS/amplification with anycast capacity and rate limiting. And DNSSEC cryptographically signs records so resolvers can detect forged answers (cache poisoning).
Design for the unhappy path: Record changed → wait out the TTL (lower it first). Name doesn't exist → negative-cache the NXDOMAIN. Under attack → anycast + rate limit. Answer forged → DNSSEC signatures. The elegant core (hierarchy + cache) needs these guards to survive the real, hostile internet.
You did it
You just designed DNS.
- O — n
- A —
- A —
- R — e
- C — a
- R — e
- G — e