DNS in practice
covers the resolution path · record types (A/CNAME/MX/TXT/SRV) · TTL and negative caching · the propagation myth · failover and health checks · debugging with dig
How a DNS lookup resolves a name
Your machine barely does DNS itself. A stub resolver in the OS hands the whole question to a recursive resolver (your ISP's, or 8.8.8.8, or 1.1.1.1) with one instruction: come back with the final answer, not a referral. That resolver is the one that walks the hierarchy.
If nothing is cached, the walk is iterative. The resolver asks a root server, which does not know api.example.com but does know who runs .com, so it refers the resolver to the .com servers. Those refer it to the servers listed for example.com. The last hop is the domain's authoritative server, which actually holds the record and returns the address. Every referral is a step closer; only the authoritative server gives a real answer.
That whole walk happens once. The resolver caches the answer for its TTL, so the next user asking the same resolver gets it back in one hop with no root or TLD traffic. Caching sits at several layers on the way to you: the recursive resolver, the OS stub, and often the browser, each holding the record until its TTL runs out. Most lookups you make never leave a cache near you.
Wrong "my computer queries the root servers for every domain." Your stub resolver delegates to a recursive resolver, and the recursive resolver only touches the root when the answer is not already cached, which is rare for popular names.
The record types you set most weeks
A DNS zone is a set of records keyed by name and type. The ones you touch:
| Type | Holds | Used for |
|---|---|---|
| A | an IPv4 address | name to server |
| AAAA | an IPv6 address | name to server (v6) |
| CNAME | another name (an alias) | point one name at a canonical one |
| MX | a mail host plus a preference number | where email for the domain goes |
| TXT | arbitrary text | domain verification, SPF, DKIM |
| NS | the authoritative servers for a zone | delegation |
A CNAME says "this name is an alias, go look up that other name instead". The resolver then restarts the lookup at the target. Two rules trip people up. A CNAME node can hold no other record (no A, no MX at the same name), because the alias and its canonical name must not carry conflicting data. And a lookup for www.example.com MX will follow the CNAME to its target and answer from there, since a CNAME redirects regardless of the type asked for.
Why the apex can't be a CNAME
You will eventually want the bare domain example.com (the zone apex) to point at something a provider only gives you as a hostname, like a load balancer or a CDN endpoint. A CNAME there is rejected, and knowing why beats fighting the provider over it.
The apex must publish its SOA record and its NS records: those are what make it a zone at all. A CNAME node is not allowed to hold any other data, so a CNAME cannot sit next to the mandatory SOA and NS. The fix is an ALIAS record (Route 53 calls it an alias, some providers call it ANAME or CNAME flattening). The provider resolves the target inside its own infrastructure and answers your apex query with the target's current A/AAAA addresses, so the bare domain tracks a moving hostname without ever returning a CNAME.
Wrong "just add an A record at the apex with the load balancer's IP." That IP is not yours and can change without notice, which is exactly why the provider handed you a hostname instead of an address. Hardcoding it turns into an outage the day it rotates.
DNS changes aren't propagation, they're caches expiring
Change a record and the authoritative server serves the new value immediately. There is no push, no ripple spreading across the internet. What you wait for is the old value aging out of caches that already have it. A resolver holding your record keeps returning the stale value until its TTL expires, then queries fresh and picks up the change.
So the delay is just the TTL you set. The 24-to-48-hour figure is a leftover from when default TTLs were a full day. Before a planned migration, lower the record's TTL well ahead of the cutover (to 60 to 300s), let the old high TTL drain out of caches, then flip the record. Raise the TTL back afterward so you are not paying for constant lookups.
Wrong "flush the authoritative server and the change goes out faster." The authoritative server already holds the new value; it is the caches downstream, which you do not control, that are still serving the old one. The only thing that clears them is time.
Negative caching, and the subdomain that won't appear
Resolvers cache absence, not just presence. When a name does not exist the authoritative server returns NXDOMAIN (the name itself is not in the zone); when the name exists but has no record of the type asked for, that is NODATA (RFC 2308 treats it as a distinct case, inferred from the response rather than a separate response code). Both get cached, so the resolver can answer "still nothing" without re-querying.
How long it caches the absence is set by the zone's SOA record, not by the missing record (there is no record to carry a TTL):
negative TTL = min(SOA.MINIMUM field, TTL of the SOA record)
RFC 2308 puts a sensible default at one to three hours and calls values over a day problematic. A negative answer that arrives without an SOA should not be cached at all, since there is nothing to bound it.
This is the failure mode behind "I created the subdomain but it 404s DNS for everyone else": your own resolver looked up new.example.com before it existed, cached the NXDOMAIN, and will keep returning it for the negative TTL even though the record is now live on the authoritative server. Waiting it out or querying the authoritative server directly is the tell. The lesson for automation: do not probe a name you are about to create, because the probe poisons caches with its non-existence.
What actually sets DNS failover time
Health-checked records let DNS route around a dead origin: the provider stops returning an endpoint once its health check fails, and hands out a standby instead. In Route 53's model, health checkers spread across many locations probe on a 10s or 30s interval, and the endpoint counts as healthy while more than 18% of checkers agree (chosen so one isolated region cannot condemn a live endpoint). Active-passive returns a primary and falls back to a standby; active-active returns every healthy endpoint and drops the ones that fail.
The trap is treating this as a fast switch. Real cutover time is two costs stacked. Detection: the provider only marks an endpoint down after a run of failed checks (failure threshold times interval). Cache expiry: even after that, the provider only changes what it answers for new queries, so any resolver holding the old record serves it until the record's TTL runs out, and OS, browser, and corporate-resolver caches stretch the tail further.
Wrong "set TTL to 0 and failover is instant." Many recursive resolvers enforce a minimum-TTL floor or ignore very low values and cache anyway, so 0 does not mean zero caching. It also turns every request into an uncached lookup, spiking query volume, cost, and per-request latency. A realistic low TTL is 30 to 60s, traded against that load. One more gap: an HTTPS health check confirms a TCP connection and a 2xx/3xx status, but Route 53's HTTPS checks do not validate the certificate, so an expired cert passes the check while browsers reject the site.
Because the caches that gate all of this sit outside your control, DNS failover is best-effort and coarse. When the recovery target is sub-second or must be guaranteed, put the failover decision below DNS at a single control point that redirects without waiting on cache expiry: an anycast VIP, a load balancer with health checks in front of both origins, or a withdrawn BGP route. DNS failover earns its place at the regional or datacenter granularity, where minutes of tolerance are fine.
SRV records and service discovery
An SRV record advertises where a named service runs, not just an address. The name encodes the service and protocol, and the record carries four fields:
_sip._tcp.example.com. 3600 IN SRV 10 60 5060 sipserver.example.com.
| | | |
priority -+ | | +- target host
weight ---+ +------ port
A client contacts the reachable target with the lowest priority number first, and spreads load across equal-priority targets in proportion to their weight. The target must have its own A/AAAA records and must not itself be an alias. SRV is how clients discover ports and hosts for protocols like SIP, XMPP, LDAP, and Kubernetes internal services, so moving a service to a new host or port is a record edit rather than a client change.
Split-horizon DNS
Split-horizon (also split-brain or split-view) serves different answers for the same name based on where the query came from, usually the source IP. Internally, db.example.com resolves to a private RFC 1918 address; from the public internet the same name resolves to a public address or does not resolve at all. Two zone files for one name, selected by the requester.
It is common for keeping internal topology private and routing staff to internal endpoints, but it bites in specific ways. A laptop that resolved the internal view and cached it will keep hitting a private address after it leaves the network, until the entry expires. And certificate validation is done against the name, not the view, so a service reachable under one name from both sides needs a certificate valid for that name regardless of which IP the view returned.
Reading dig +trace: authoritative vs cached
The core debugging skill is knowing whether an answer came from an authoritative server or a cache. In a normal dig the aa flag in the header marks an authoritative answer; its absence means a resolver served it from cache, so the TTL you see is counting down, not the record's full value.
dig +short api.example.com # what your resolver returns (may be cached)
dig @ns1.example.com api.example.com +norec # ask the authoritative server, no recursion
dig +trace api.example.com # iterative walk from the root
dig +trace starts at the root and follows delegations down, reporting each referral (root to TLD to the zone's nameservers to the final answer). It ignores your recursive resolver's cache by design, so it shows what a fresh resolution would find, which is how you catch a resolver serving a stale record that the authoritative servers no longer publish. Two caveats: +trace does not exactly reproduce a real resolver's behavior (a resolver leans on its cache and configuration), and it may still use the servers in resolv.conf to bootstrap the root nameserver list. When authoritative and cached answers disagree, the cached side is stale and you are watching a TTL, or a negative cache, that has not expired.
dig deeper
Primary sources behind these notes - the specs and official docs worth reading in full.
gapmap pro
You've read the DNS in practice notes. An interviewer will ask you to prove them.
Know you're ready. Don't hope.
The notes are free: every topic, senior depth. Pro is what turns reading into readiness you can prove:
Mock interviews on your topics
An AI interviewer that pushes back with follow-ups and grades you honestly. Per module, fair-use unlimited.
Voice test interviews
The dress rehearsal, out loud: questions from your map, a transcript, and a per-answer verdict.
A plan to your date
Ready or not ready, per module, as the interview approaches. Recomposed whenever your goal changes.
A mentor inside every lesson
Stuck on the senior notes? Ask, drill deeper, get re-quizzed on the spot.
Pro $20/mo · Pro+ $50/mo · every study note on the site stays free