Hermes Wiki
Developer/Networking/DNS/Fundamentals/dns-resolution-records-and-ttl

DNS Resolution, Record Types, and TTL

Concept

DNS (Domain Name System) translates human-readable hostnames into the IP addresses machines actually connect to. A full, uncached lookup for www.example.com walks a chain of servers: the client's stub resolver asks a recursive resolver (run by the OS/ISP or a public service like 1.1.1.1/8.8.8.8), which queries a root server (returns the address of the .com TLD server), then the TLD server (returns the address of example.com's authoritative nameserver), then that authoritative server, which finally returns the actual record. The recursive resolver caches the result and returns it to the client. Every step after the first can be skipped once its result is cached — which is the entire reason caching and TTL exist: a cold lookup takes several round trips, a warm one takes zero.

Record types encode different answers to "what does this name mean": an A record maps a name to an IPv4 address, AAAA to IPv6, CNAME aliases one name to another (cannot coexist with other records on the same name, which is why apex/root domains often can't use a CNAME and need an A record or a provider-specific "ALIAS/ANAME" record instead), MX points at mail servers with a priority, TXT holds arbitrary text (used for domain verification and, critically, for SPF/DKIM/DMARC email-authentication policy), and NS delegates a subdomain (or the whole domain) to a different set of authoritative nameservers.

TTL (Time to Live) is a field on every DNS record, in seconds, telling every resolver and client along the chain how long they're allowed to cache that record before re-querying the authoritative server. TTL is the single lever that controls the tradeoff between lookup speed/authoritative-server load (favors long TTL) and how fast a change actually reaches users (favors short TTL) — there is no way to get both. What's commonly called "DNS propagation delay" is largely a myth in the sense that records don't actually spread outward like a wave; what actually happens is that every resolver that already cached the old value keeps serving it, independently, until its own copy of the TTL expires — so a change appears to "propagate" only because different caches expire at different times, all bounded by whatever TTL was set on the old record before the change.

Tradeoffs

TTL choice Benefit Cost
Long TTL (hours/days) Fewer lookups hit the authoritative server (lower load, lower cost on paid DNS providers); faster average resolution for end users since more requests hit a warm cache A record change (e.g. an IP change during a cutover or incident) takes up to the full TTL to reach every cached resolver — during an incident this directly extends impact
Short TTL (seconds/low minutes) Changes propagate to (i.e., are re-fetched by) caches almost immediately — critical during a planned cutover or an active incident requiring a fast IP change Far more queries hit the authoritative nameserver; on a heavily-cached record this can meaningfully increase both latency variance and DNS provider query costs at scale
CNAME to a provider endpoint vs. static A record The provider can change its own IPs freely without you ever needing a DNS change (common with CDNs/load balancers) Adds one extra resolution hop per lookup (resolve the CNAME, then resolve the target), and you're bound by the CNAME restriction (can't coexist with other record types on the same name — most apex domains can't do this at all)

The practical playbook this produces: keep TTLs long for records that rarely change (lower cost, faster typical resolution), and lower a specific record's TTL in advance of any planned change — well before the old TTL's worth of caches would otherwise need to expire — so that by the time the actual cutover happens, every cache is already re-querying frequently and the real change lands fast.

When to use / when not to

  • Plan ahead for any domain cutover, DNS provider migration, or load-balancer/IP change: lower the TTL on the affected record(s) at least one full old-TTL-period before the change, make the change, verify propagation, then raise the TTL back once stable.
  • Use short TTLs by default on records tied to infrastructure that might need emergency failover (e.g. a manually-managed failover IP) — the cost of extra queries is worth the ability to react fast during an incident.
  • Don't run every record at a uniformly short TTL "just in case" — for a stable, rarely-changing record (like an MX record for a mail provider that's been in place for years) this only adds authoritative-server load and query cost for no real benefit.
  • Don't assume a DNS change has "propagated" globally just because your own machine sees it — other resolvers with a still-live cache of the old record will keep answering with the stale value until their independent TTL expires; this is per-resolver, not a global synchronized wave.

Common pitfall

Changing a record without lowering its TTL beforehand, then being surprised that a meaningful fraction of users still hit the old IP/target for hours after the "fix" is live — because every resolver that cached the record under the old, longer TTL keeps serving that cached answer until its own expiry, regardless of when the authoritative record actually changed. The fix has to happen before the change: lower the TTL, wait out the old TTL's duration so live caches expire and re-fetch under the new short TTL, then make the actual change.

Engineering Lens

DNS TTL is a small, easy-to-overlook instance of a much bigger operational habit: understanding the caching layers between "I changed something" and "users see the new state," and sequencing changes around them instead of discovering the lag mid-incident. The same discipline that says "lower the TTL a day before a planned cutover" is the same instinct behind warming a CDN cache before a traffic spike or staggering a config rollout — treat every cache in the path as a real delay to plan around, not an implementation detail to ignore until it causes an outage.

Sources

Hermes Wiki