The whole design, in writing
Learn system design by building the Domain Name System step by step. An interactive guide covering why one central name→IP table can't work, a delegated hierarchy of root / TLD / authoritative servers, recursive resolution, caching with TTL, replication and anycast for availability, GeoDNS and latency-based routing, and the unhappy paths (propagation, negative caching, DDoS, DNSSEC).
Every step of the build above, written out: the problem each piece solves, the option that was taken and the ones that were not, the numbers, and how it fails in production.
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.
What the new pieces do
- Clientclient
- A browser (its OS stub resolver) that has a name like vibeengines.com and needs the IP address to connect to.
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?
One central name→IP table for the whole internet. What breaks first?
Building it once isn't the problem. The problems are load, failure, and ownership: one server can't take the planet's query rate, is a single point of failure, and no single entity can be trusted to own every name.
Address exhaustion is a separate concern (IPv6). The naive table fails for reasons of scale, availability and control, not address space.
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 this piece earns its place
The obvious rescue for the central table is to shard it — a hundred machines behind a load balancer, still one operator. That fixes exactly one of the three problems. Load spreads, but the shard map is a global index somebody has to publish and keep consistent, and it is still one organisation deciding which names exist and which resolve. Delegation is different in kind: the name’s own dotted structure is the shard map, so there is nothing to publish, and each slice is run by whoever owns it. What that buys costs something honest, and I would say it out loud — correctness now depends on thousands of independent operators nobody controls, and a zone whose owner runs it badly is badly run for everyone who visits it. The system trades one failure it cannot survive for many small ones it can: a bad zone takes out one name, not the internet. That is the whole argument for hierarchy over 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?
If no single server has the answer, who does the multi-step lookup for the client?
Making every stub device chase the hierarchy is wasteful and un-cacheable across users. You want a shared component that does the walk once and caches for everyone.
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.
The root doesn't hold final IPs (it would be the central table again) — it only points to TLDs. A resolver is needed to follow those pointers down the tree.
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.
Why this piece earns its place
Handing the walk to a shared resolver concentrates something. Every client behind it inherits its outages, its policy and its view of the namespace, and it sees every name those clients look up — which makes it the natural place to log, filter or redirect. One bad entry in its memory is wrong for everybody behind it rather than for one laptop. So the resolver is the component here most worth treating as replaceable: stubs are configured with more than one, they fall back when the first stops answering, and on a hostile network the resolver handed out by DHCP is exactly the thing quietly substituted. The design does not remove that risk, it moves it somewhere a user can choose. The reason it is still the right call is that the alternative spreads the same trust across every device while sharing nothing — each one walking the tree itself multiplies upstream load by the number of devices and reuses not a single answer.
What the new pieces do
- Recursive Resolverresolver
- The workhorse (your ISP's or 8.8.8.8). Does the legwork: walks the hierarchy on your behalf and returns the final answer.
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?
How is the name space organized so no server holds everything?
An alphabetical shard has no natural owner per name and still needs a global index to find the right shard. DNS uses the name's own structure — its dotted parts — to delegate ownership.
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.
A central directory of locations is just the central table again, one indirection removed. The hierarchy needs no global index — the name itself tells you where to go next.
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.
Why this piece earns its place
This step bakes in an assumption worth naming: a zone is only as reachable as everything above it, and as everything its nameservers themselves depend on. Delegation gives each level independence in what it publishes, not independence in failure. If the parent’s delegation is wrong or withdrawn, the zone answers perfectly and nobody can find it, because resolvers never arrive. The same is true one step sideways — nameserver names live in some zone too, and if that zone is a domain someone forgot to renew, the delegation points at nothing, or at whoever registers it next. The practical rule that falls out is to verify the delegation from the outside rather than trusting your own servers’ view of it, and to keep nameserver names in a zone you would notice expiring. Ownership in DNS is delegated downward, which also means it can be revoked or fumbled upward, and no amount of redundancy inside a zone defends against that.
- root→ TLD
- TLD→ authoritative
- auth→ the record
What the new pieces do
- Root Serversdata
- The top of the tree. Doesn't know vibeengines.com, but knows which servers run .com. 13 anycast identities worldwide.
- TLD Serversdata
- The .com registry servers. Don't hold the final IP, but know which authoritative nameserver owns vibeengines.com.
- Authoritative NSdata
- The nameserver that actually owns the zone. It holds the real records (A/AAAA/CNAME) and gives the final answer.
Back of the envelope
- root delegates TLDs
- knows who runs .com/.org/…
- TLD delegates zones
- knows vibeengines.com's NS
- authoritative holds records
- A / AAAA / CNAME / MX
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.
Why this piece earns its place
Three hops is the best case, and it is the parent’s glue that keeps it there. A delegation names nameservers, it does not give their addresses, so if a zone’s nameservers are named inside the zone they serve, the resolver needs the address of a server it can only learn by asking that server — the loop glue records in the parent exist to break. Name them out of zone instead and the walk quietly grows an extra resolution before it can even ask the real question. The other thing worth saying is what a cold walk actually costs. It is not three cheap hops, it is three chances to land on a slow or silent server, and the user experiences the total as a page that will not start. That is why a resolver keeps a round-trip estimate per nameserver and prefers the fastest one that has been answering, and why every level insists on more than one address to try.
- 3 hopsroot → TLD → auth
- root hintsknown in advance
- A recordthe final IP
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?
A full walk every lookup would be slow and crush the root/TLDs. What saves it?
No server is fast enough to answer the whole internet's queries directly — that's the central-table trap again. The load must be kept away from the root entirely.
Names are looked up constantly across billions of users. What makes it cheap isn't rarity — it's that answers are reused via caching for a bounded time.
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.
Why this piece earns its place
Two TTLs decide how fast a change lands, and only one of them is yours. Records inside the zone carry a TTL their owner sets; the delegation pointing at your nameservers carries one the parent sets, and it is usually far longer — so moving a name to a new address is quick, while moving it to new nameservers is not. Setting the record TTL is a real dial with a cost in both directions. Long means fewer walks, faster answers, and the part people forget: an authoritative outage nobody notices, because cached copies keep resolving for as long as it lasts. Short means you can move quickly, but every expiry puts the full walk back in a user’s request path and makes your nameservers’ availability directly visible to them. So the usual shape is long by default, lowered deliberately ahead of a planned change and raised again afterwards. The exception is a name whose failover is automatic rather than planned: nobody gets to pre-lower a TTL for an outage they did not schedule, so there the short TTL is the mechanism and you pay its cost permanently.
- ~90%+served from cache
- TTLowner-set freshness
- 0 hopson a cache hit
What the new pieces do
- Resolver Cachecache
- Remembers recent answers until their TTL expires. Most lookups are served straight from here — the reason DNS feels instant.
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?
The root/TLD/authoritative servers are critical. How do you make them survive failure and attack?
One box, however powerful, is still one target and one failure. DNS availability comes from many redundant servers answering as one, not a single fortress.
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.
Caching reduces load but records still expire and new names still need the hierarchy — the servers must be reachable. Availability of the servers themselves requires replication + anycast.
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.
Why this piece earns its place
Anycast moves the failure domain into routing, and routing announces reachability, not health. A node that is up but answering badly — a bad config push, a full disk, a process that accepts queries and never replies — keeps attracting everything routed to it, and it is a black hole for precisely the users nearest to it while the global picture still looks fine. So the health check has to control the announcement: a node failing its own check withdraws its route and lets the network deliver those queries elsewhere. That is the mechanism that turns losing a node into a non-event; without it, anycast just spreads a broken answer efficiently. The second thing this step assumes is that the redundancy is real. Two nameservers are two failure domains only if they are genuinely separate — different networks, different providers, ideally different software — because two names on one provider share its outages, its routing and its control plane, and count as one.
- 13 → 100sroot identities → machines
- ≥2authoritative NS per zone
- anycastnearest healthy answers
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).
Why this piece earns its place
Steering answers a question it cannot quite ask: the authoritative server sees the resolver’s address, not the user’s. Someone on a large public resolver looks like wherever that resolver’s nearest node happens to be, which may be nothing like where they are — and the answer they get is then cached and handed to everyone else behind that same resolver. The unit of steering is a resolver’s user base, not a user. That is fine for coarse routing and misleading for anything that assumes precision. The partial fix is passing a truncated client subnet along with the query, and it costs on both sides: the cache now holds an entry per subnet instead of one per name, which eats into the hit rate that makes DNS cheap in the first place, and it tells every authoritative server roughly where the asker sits. Worth turning on for the latency-sensitive names and leaving off everywhere else.
What the new pieces do
- GeoDNSservice
- Traffic management on the authoritative side: return a different IP based on the asker's location or server health.
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).
Why this piece earns its place
Signing changes a zone from fail-open to fail-closed, and that is the part to plan for. An unsigned zone with a mistake in it serves a wrong answer; a signed zone whose signatures have expired, or whose key no longer matches the record held one level up, serves nothing to validating resolvers while resolvers that do not validate carry on perfectly. It arrives as an outage only some users have, which your own checks may not reproduce. Signatures carry a validity window, so that is a clock running whether anyone is watching it or not, and key rollovers have to be coordinated with the level above rather than done alone. Signing also makes answers much larger, which pushes them past what fits in one UDP packet into truncation and a TCP retry, and makes the zone a more attractive amplifier for the reflection attacks named in the same breath — response rate limiting exists because of that, not despite it.
What the new pieces do
- Registrar / Zonecontrol
- Where the domain owner edits records. Changes propagate outward as caches expire — not instantly.
You did it
You just designed DNS.
Everything you assembled, in order
- One central name→IP table fails on load, availability and control — so split and delegate it.
- A recursive resolver does the multi-step walk so clients stay dumb (a stub resolver).
- A delegated hierarchy: root → TLD → authoritative, each owning and pointing down one level.
- Resolution follows referrals from the root hints down to an authoritative A record.
- Caching with owner-set TTLs serves most lookups instantly and shields the hierarchy.
- Replication + anycast make the root, TLDs and zones self-healing and DDoS-resistant.
- GeoDNS steers users to nearby/healthy servers; DNSSEC, negative caching and low TTLs handle the edges.