DNS
DNS is the internet's phone book — it turns the names humans use into the addresses machines route to — and it's also the internet's most common outage cause and a frequent source of baffling latency. "It's always DNS" is a running joke among engineers precisely because DNS is invisible until it breaks, and then it breaks everything.
Before any TCP handshake or HTTP request, one thing has to happen: your machine needs the IP address of the server it’s trying to reach, and all it has is a name like example.com. DNS (the Domain Name System) is the distributed system that resolves names to addresses. This post covers how resolution works, the record types you’ll actually configure, the caching that makes it fast (and occasionally maddening), and why DNS is such a frequent culprit in outages and latency.
The problem DNS solves
Humans use names (example.com); the network routes on IP addresses (203.0.113.10, from the IP post). DNS is the translation layer between them — a globally distributed database mapping names to addresses (and other records). Its job sounds simple but is remarkable in scale: it must answer billions of lookups a second, stay available globally, and let anyone update their own names — with no central server holding everything. It achieves this by being a distributed, hierarchical, heavily-cached system, and each of those properties explains part of its behavior.
How resolution works
Resolving a name walks a hierarchy of servers, from the most general to the most specific:
Your app wants example.com →
1. Resolver (your ISP's or a public one like 1.1.1.1) — does the legwork, caches results
2. Root servers → "ask the .com servers"
3. TLD servers (.com) → "ask example.com's authoritative servers"
4. Authoritative servers for example.com → "example.com is 203.0.113.10"
→ resolver returns the address to your app (and caches it)
- The resolver (recursive resolver) does the work on your behalf — your machine asks it, and it queries the hierarchy and returns the answer. It’s usually run by your ISP or a public provider (like
1.1.1.1or8.8.8.8). - Root → TLD → authoritative — the resolver walks down: root servers point to the top-level domain (TLD) servers for
.com, which point to the authoritative servers forexample.com, which hold the actual answer. Each level knows only the next level down — the hierarchy is what makes a global namespace manageable without any single server knowing everything. - Authoritative servers are the source of truth for a domain — where you configure your records. Everyone else caches copies.
This walk happens (mostly) over UDP (from the TCP/UDP post) — small request, small response, where TCP’s handshake overhead would be wasteful — which is one reason DNS is fast when it’s cached and why it’s a classic UDP use case.
The record types you’ll use
DNS holds several record types; a handful matter for everyday backend work:
- A record — maps a name to an IPv4 address (
example.com → 203.0.113.10). The fundamental record. - AAAA record — maps a name to an IPv6 address. Same job, IPv6.
- CNAME record — an alias pointing one name to another name (
www.example.com → example.com), so you manage the address in one place. Common for pointing subdomains at a provider’s hostname. - MX record — mail exchange, directing email for the domain to mail servers.
- TXT record — arbitrary text, used for domain verification (proving you own a domain — as this blog’s own setup uses) and email authentication (SPF/DKIM).
- NS record — delegates a domain to its authoritative name servers.
Configuring these correctly is the substance of “DNS setup” for most engineers: an A/AAAA (or CNAME) to point your domain at your server/CDN, MX for mail, TXT for verification. Getting a record wrong — or waiting for it to propagate — is a routine source of “the site works for me but not for them.”
Caching and TTL: fast, but with a lag
DNS is fast because results are cached at every level — the resolver, the operating system, and the browser all cache answers so most lookups never traverse the full hierarchy. Each record has a TTL (time-to-live) telling caches how long to keep it before re-querying:
- High TTL — answers cached longer → faster (fewer lookups) and more resilient, but changes take longer to take effect everywhere.
- Low TTL — changes propagate quickly, but more lookups (slightly more latency and load).
This caching is a double-edged sword and the source of DNS’s most infamous behavior — propagation delay. When you change a DNS record, caches around the world keep serving the old value until their TTL expires, so the change appears to “propagate” gradually over minutes to (with high TTLs) up to a day or more. This is why:
- A DNS change doesn’t take effect instantly, and different users see the change at different times.
- Before a planned change (a migration), you lower the TTL in advance so caches expire quickly when you cut over.
- “It works for me but not for them” during a DNS change is usually cache/TTL differences, not a real failure.
Understanding TTL and propagation is what turns DNS changes from mysterious and scary into predictable and planned.
Why “it’s always DNS”
DNS has an outsized reputation for causing problems, and the reasons are structural — worth knowing so you check DNS early when debugging:
- It’s a dependency for everything. Nearly every connection starts with a DNS lookup, so when DNS fails, everything fails at once, dramatically. A DNS outage looks like a total outage even though the servers are fine — the classic “the whole site is down” that turns out to be DNS.
- Caching hides and delays problems. A bad record change might not affect you (cached) while breaking others (expired), and might “fix itself” as caches expire — making problems intermittent and confusing.
- Misconfigurations are easy and impactful. A wrong record, a typo, a forgotten TTL, or a lapsed domain registration takes down access instantly and globally.
- It adds latency to the first request. An uncached DNS lookup adds a round-trip (or several, walking the hierarchy) before the TCP handshake even starts — a real component of first-request latency, mitigated by caching and by keeping resolution fast.
The practical wisdom encoded in “it’s always DNS”: when something is mysteriously broken, unreachable, or slow-to-first-byte — check DNS first. Verify the name resolves, resolves to the right address, and isn’t mid-propagation. A large share of “the network is broken” incidents are really DNS, and it’s the cheapest thing to rule out. DNS resolved, the connection can proceed — next, securing it with TLS.
Key takeaways
- DNS is the internet’s distributed, hierarchical, cached phone book, translating human names (example.com) into the IP addresses the network routes on — answering billions of lookups with no central server holding everything.
- Resolution walks a hierarchy: a recursive resolver queries root → TLD (.com) → authoritative servers (the domain’s source of truth), each level pointing to the next; it runs mostly over UDP for efficiency.
- The everyday record types are A/AAAA (name → IPv4/IPv6), CNAME (alias to another name), MX (mail), TXT (verification, email auth), and NS (delegation) — configuring these correctly is most of “DNS setup.”
- Caching with TTLs makes DNS fast but causes propagation delay: changing a record leaves caches serving the old value until their TTL expires, so lower TTLs before a planned change and expect changes to roll out gradually and unevenly.
- “It’s always DNS” is real because DNS is a dependency for nearly every connection (so its failure looks like a total outage), caching makes problems intermittent, misconfigurations are easy and global, and lookups add first-request latency — so check DNS first when debugging.