You type example.com into your browser and hit enter. The page loads. It took maybe 200 milliseconds. You didn’t think about it.
In those 200 milliseconds, your computer talked to at least four different servers, traversed a hierarchy designed in 1983, and relied on a caching system so aggressive that most queries never reach their destination. All of it invisible. All of it happening in the gap between your keypress and the first pixel on screen.
The Query Starts Closer Than You Think
Before anything touches the network, your operating system checks the cheap answers.
First, /etc/hosts — a flat file that maps hostnames to IP addresses directly. It’s a relic from when the entire internet fit in a text file. It still runs before every DNS query, which is why it’s useful for local development and why malware sometimes modifies it.
Then the OS cache. Did you visit this domain recently? Is there a cached answer that hasn’t expired? If yes, done. No network request. Sub-millisecond.
If neither has the answer, the application calls getaddrinfo() — the standard library function that resolves a hostname to an IP. This is where DNS begins.
Your machine doesn’t do DNS resolution itself. It delegates. The stub resolver — a lightweight DNS client built into your OS — takes the query and forwards it to a recursive resolver. Which one? Whatever is configured: your router, your ISP’s resolver, or a public one like 8.8.8.8 or 1.1.1.1.
The stub sends a single UDP packet. “What’s the A record for example.com?” Then it waits. Everything that follows happens on the recursive resolver’s side.
The Recursive Resolver’s Cache
The recursive resolver checks its own cache first. A busy resolver like 8.8.8.8 handles trillions of queries and caches aggressively. If someone else asked for example.com recently, the answer is already there. Response goes back. Total time: maybe 1-5 milliseconds.
Most queries end here. The caching layer absorbs the vast majority of DNS traffic. If you’re accessing a popular domain, the recursive resolver almost certainly has a cached answer.
But say it doesn’t. Cache is empty. Now the resolver has to go find the answer from scratch.
Walking the Tree
DNS is a hierarchy. Root zone at the top. TLDs below (.com, .org, .net). Authoritative nameservers for individual domains below that. The recursive resolver walks this tree top-down.
First stop: the root. The resolver asks a root server, “What’s the A record for example.com?” The root doesn’t know — it doesn’t store individual domain records. But it knows who handles .com, so it responds with a referral: “Ask these nameservers.”
There are 13 logical root servers, labeled A through M. In reality, over 1,500 physical instances distributed worldwide using anycast — a routing technique where the same IP address is served by different machines depending on your location. When your resolver talks to “a root server,” it’s talking to whichever physical instance is closest. The resolver already has root addresses cached (they barely change), so this step is fast. One round-trip.
Second stop: the TLD. The resolver asks a .com server. Same pattern: doesn’t have the final answer, but knows which nameservers are authoritative for example.com. Returns a referral. One more round-trip.
Third stop: the authoritative nameserver. The resolver asks directly. This server has the actual record. It responds with the IP address. Final round-trip.
The resolver caches the answer using the TTL (Time To Live) in the record, sends it to your stub resolver, which sends it to your application, which opens a TCP connection to the IP.
Three round-trips for a fully uncached query. In practice, TLD referrals are almost always cached, so a “cold” query for a new domain under a common TLD usually needs one or two hops.
The 50 Millisecond Budget
Each round-trip takes roughly 5-30 milliseconds depending on geographic distance. Fully uncached: 50-200 milliseconds. Partially cached (common case): 10-50 milliseconds. Fully cached: under a millisecond.
This is why TTLs matter. A 300-second TTL (5 minutes) means the resolver re-queries every 5 minutes. A 86400-second TTL (24 hours) means once a day. Shorter TTLs mean fresher data but more latency on expired caches. Longer TTLs mean faster responses but slower propagation when you change records.
When people say “DNS propagation takes 24-48 hours,” what they actually mean is caches around the world are holding the old answer until the TTL expires. There’s no propagation mechanism. Old caches just expire at different times.
What Can Go Wrong
At each step, things can fail.
NXDOMAIN. The domain doesn’t exist. The authoritative server says so. Clean failure.
SERVFAIL. The resolver tried to get an answer and couldn’t. Maybe the authoritative server is down. Maybe DNSSEC validation failed. Maybe there’s a network issue. SERVFAIL is the generic “something broke” response, and debugging it means tracing the query at each hop.
Timeout. The resolver sent a query and got nothing back. After 2-5 seconds, it might retry with a different server. If all timeout, the query fails. The user sees a browser error page.
Poisoned cache. An attacker injects a fake response into the resolver’s cache. Everyone who queries that domain gets the fake answer. This is what DNSSEC prevents — and what makes its low adoption frustrating.
The Invisible Machine
DNS is one of the oldest protocols still running at the core of the internet. Designed when the entire network could be mapped in a single document. Handling something like 2 trillion queries per day globally.
Most developers use it hundreds of times a day without a second thought. The URL goes in, the page comes up, and the 50 milliseconds in between might as well not exist.
But they do exist. And the next time a page loads slowly for no obvious reason — check DNS first. The invisible machine might be stuttering.