DNS as a System (Part 5)
Time to Live (TTL)
Time to Live (TTL)
Introduction
DNS was designed with one principle front and center: performance at scale. With billions of devices issuing DNS queries every day, querying authoritative nameservers for every single request would be catastrophic. The solution? Caching — and the mechanism that controls it is called Time to Live (TTL).
TTL is one of the most deceptively simple yet critically important concepts in DNS. Get it right, and your DNS infrastructure is fast, efficient, and resilient. Get it wrong, and you'll face either sluggish propagation of changes or an overloaded authoritative nameserver.
The Foundation: RFC 1034
Before diving into TTL mechanics, it's worth acknowledging where this concept comes from.
RFC 1034 — Domain Names: Concepts and Facilities
──────────────────────────────────────────────────────────────
Published: November 1987
Section: 2.2 — Design Goals
Relevance: Defines DNS caching and TTL as foundational principles
Key design goals from RFC 1034:
├─ The system must be capable of being queried frequently
├─ Locally cached data should reduce load on authoritative servers
├─ TTL controls the lifetime of cached data
└─ These principles have governed DNS for nearly 40 years
What are RFCs?
├─ RFC = Request for Comments
├─ Standard documents specifying internet protocols and best practices
├─ Published by the IETF (Internet Engineering Task Force)
└─ Reading RFCs is essential for deep understanding of any protocol
The Caching Analogy
The Detective's Notebook — Caching Analogy
──────────────────────────────────────────────────────────────
Scenario: A detective solves a case and records all clues in a notebook.
Without caching (no notebook):
└─ Every similar case → start from scratch
→ Re-interview witnesses, re-visit locations, re-gather evidence
→ Slow, expensive, repetitive
With caching (notebook):
└─ Similar case arises → check notebook first
→ If relevant notes exist → answer immediately
→ Only re-investigate when notes are outdated (TTL expired)
DNS equivalent:
├─ Notebook = Resolver cache
├─ Case notes = Cached DNS records
├─ Expiration date = TTL value
└─ Re-investigating = Querying authoritative nameserver again
The Full DNS Resolution Chain
Understanding TTL requires understanding every component in the DNS resolution path — from your device to the authoritative nameserver.
Complete DNS Resolution Chain
──────────────────────────────────────────────────────────────
Step 1: Application
┌─────────────────────────────────┐
│ Your Application │
│ (Browser, curl, ping, etc.) │
│ Issues a DNS query │
└─────────────────────────────────┘
│
↓
Step 2: Stub Resolver (OS)
┌─────────────────────────────────┐
│ Stub Resolver │
│ (Built into the OS) │
│ Linux: getaddrinfo() syscall │
│ Checks OS-level DNS cache │
│ Cannot query nameservers │
│ directly — forwards upstream │
└─────────────────────────────────┘
│
↓
Step 3: Forwarding Resolver (Router)
┌─────────────────────────────────┐
│ Router / Forwarding Resolver │
│ (Your home/office router) │
│ First stop outside the device │
│ May cache responses locally │
│ Forwards to public resolver │
└─────────────────────────────────┘
│
↓
Step 4: Public Recursive Resolver
┌─────────────────────────────────┐
│ Recursive Resolver │
│ (1.1.1.1, 8.8.8.8, ISP) │
│ Performs full DNS tree walk │
│ Maintains large shared cache │
│ Caches per TTL values │
└─────────────────────────────────┘
│
↓
Step 5: Authoritative Nameservers
┌─────────────────────────────────┐
│ Root → TLD → Domain NS │
│ Final authoritative answer │
│ Only reached on cache miss │
└─────────────────────────────────┘
Where Each Layer Caches
Caching at Every Layer
──────────────────────────────────────────────────────────────
Layer Cache Location Scope
────────────────────────────────────────────────────────────────
Browser Internal DNS cache Single app
Operating System OS DNS cache (systemd-resolved, etc.) All apps on device
Router Router firmware cache All devices on network
ISP/Public Resolver Resolver cache (1.1.1.1) All users of that resolver
What Is TTL?
TTL (Time to Live) is a value attached to every DNS record that specifies — in seconds — how long a resolver is permitted to cache that record before it must re-fetch it from the authoritative nameserver.
TTL — Core Definition
──────────────────────────────────────────────────────────────
Field: TTL (Time to Live)
Unit: Seconds
Location: Present in every DNS resource record
Purpose: Controls how long cached data is considered valid
Analogy: Expiration date on a carton of milk — after this date,
discard and get fresh
When TTL expires:
├─ Cached record is marked stale and discarded
├─ Next query triggers a fresh lookup to authoritative nameserver
└─ New TTL value received and countdown restarts
Reading TTL With dig
The TTL value is visible in every dig response, right after the domain name.
bash
$ dig kodekloud.com
;; QUESTION SECTION:
;kodekloud.com. IN A
;; ANSWER SECTION:
kodekloud.com. 300 IN A 104.26.10.250
kodekloud.com. 300 IN A 104.26.11.250
kodekloud.com. 300 IN A 172.67.68.105
;; Query time: 166 msec
;; SERVER: 2806:10c0:ffff:e#53(2806:10c0:ffff::e)
TTL Field Breakdown
dig Answer Section — Field by Field
──────────────────────────────────────────────────────────────
kodekloud.com. 300 IN A 104.26.10.250
│ │ │ │ │
│ │ │ │ └─ IP address (value)
│ │ │ └─ Record type (A = IPv4)
│ │ └─ Class (IN = Internet)
│ └─ TTL: 300 seconds (5 minutes)
└─ Domain name queried
Interpretation:
├─ This record will be cached for 300 seconds
├─ After 300 seconds, the resolver discards it
└─ Next query after expiry hits the authoritative nameserver
Watching TTL Count Down
# Query the same domain twice within the TTL window
# The second response's TTL will be lower — it's counting down
$ dig kodekloud.com | grep -A3 "ANSWER SECTION"
kodekloud.com. 300 IN A 104.26.10.250 ← fresh cache
# Wait 60 seconds, query again
$ dig kodekloud.com | grep -A3 "ANSWER SECTION"
kodekloud.com. 240 IN A 104.26.10.250 ← 60s consumed
# When TTL reaches 0 → resolver fetches fresh record
TTL Values: The Trade-Off
Setting the right TTL is a balancing act between freshness and performance.
High TTL — Pros and Cons
High TTL (e.g., 86400 seconds = 24 hours)
──────────────────────────────────────────────────────────────
Pros:
├─ Fewer queries to authoritative nameserver
├─ Faster responses (more cache hits)
├─ Lower infrastructure cost and load
└─ Better resilience (cached even if NS goes down briefly)
Cons:
├─ Slow propagation when records change
├─ Users may get outdated IP addresses for up to 24 hours
├─ DNS migrations (changing nameservers) take longer to propagate
└─ If you update an A record, old IP serves traffic until TTL expires
Low TTL — Pros and Cons
Low TTL (e.g., 60 seconds = 1 minute)
──────────────────────────────────────────────────────────────
Pros:
├─ Fast propagation of record changes
├─ Quick failover to new IPs
└─ Useful during planned migrations or deployments
Cons:
├─ More frequent queries to authoritative nameserver
├─ Higher server load and bandwidth usage
├─ Slower responses (more cache misses)
└─ Negates many benefits of caching infrastructure
TTL Comparison Table
| TTL Value | Duration | Use Case |
|---|---|---|
| 60s | 1 minute | Active migrations, frequent IP changes |
| 300s | 5 minutes | Dynamic content, CDN, load-balanced IPs |
| 3600s | 1 hour | Standard web services |
| 86400s | 24 hours | Stable infrastructure, rarely changed records |
| 604800s | 7 days | Highly stable records (MX, NS records) |
The Pre-Migration Best Practice
TTL Strategy for DNS Migrations
──────────────────────────────────────────────────────────────
Problem: You want to change your A record IP with minimal downtime
Wrong approach:
├─ TTL = 86400 (24 hours)
├─ Change IP immediately
└─ Users stuck on old IP for up to 24 hours
Right approach:
├─ Step 1: Lower TTL to 300s well in advance (48–72 hours before)
│ → Allows existing 24h caches to expire
│ → New queries now cache for only 5 minutes
├─ Step 2: Make the IP change
└─ Step 3: New IP propagates globally within 5 minutes ✅
Raise TTL back to 86400 after migration completes
TTL in Private Networks
DNS caching doesn't just happen at the resolver level — it also occurs within private networks at multiple independent layers, which can cause unexpected inconsistencies.
Multiple Cache Layers on a Single Device
Caching Layers Within a Single Device
──────────────────────────────────────────────────────────────
Application Layer:
├─ Web browsers (Chrome, Firefox) maintain their own DNS cache
├─ May apply their own TTL minimums (Chrome enforces min 1s)
└─ Flushing browser cache doesn't clear OS cache
Operating System Layer:
├─ Linux: systemd-resolved, nscd
├─ macOS: mDNSResponder
├─ Windows: DNS Client service
└─ Shared across all apps — but each app may override
Result:
├─ Same domain may resolve differently in browser vs. ping vs. curl
├─ One app sees new IP, another still uses old cached IP
└─ Can cause confusing, hard-to-diagnose issues
The Inconsistency Problem
Real-World Scenario — DNS Inconsistency
──────────────────────────────────────────────────────────────
You update your server's A record to a new IP.
Device behavior after update:
├─ ping kodekloud.com → Uses OS cache → returns OLD IP
├─ curl kodekloud.com → Uses OS cache → returns OLD IP
├─ Chrome browser → Uses browser cache → returns OLD IP
└─ Firefox → Browser cache expired → returns NEW IP
Why?
├─ Each application/layer cached the record at a different time
├─ Each has different cache expiry timing
└─ TTL countdown started at different moments for each
This is NOT a DNS problem — it's expected cache behavior.
Applications That Ignore TTL
TTL Non-Compliance in Applications
──────────────────────────────────────────────────────────────
Some applications override or ignore DNS TTLs:
Java applications:
└─ Historically cached DNS forever (networkaddress.cache.ttl = -1)
→ Required JVM restart to pick up DNS changes
Some older HTTP clients:
└─ Cache DNS for the lifetime of a connection pool
→ Ignores TTL entirely
CDN and proxy servers:
└─ May enforce minimum TTL regardless of record value
→ Cloudflare enforces minimum 30s TTL
Impact:
├─ DNS record changes propagate to most resolvers quickly
├─ But non-compliant apps may serve stale data for much longer
└─ Critical to know your application's DNS caching behavior
Clearing DNS Caches — Troubleshooting
When DNS issues arise, clearing caches at each layer is a key troubleshooting step.
Clearing OS-Level DNS Cache
# Linux (systemd-resolved)
$ sudo systemd-resolve --flush-caches
# Verify cache was cleared
$ sudo systemd-resolve --statistics | grep "Cache"
# Linux (nscd)
$ sudo service nscd restart
# macOS
$ sudo dscacheutil -flushcache
$ sudo killall -HUP mDNSResponder
# Windows
> ipconfig /flushdns
Clearing Browser DNS Cache
Browser DNS Cache Clearing
──────────────────────────────────────────────────────────────
Chrome:
└─ Navigate to: chrome://net-internals/#dns
Click: "Clear host cache"
Firefox:
└─ about:config → network.dnsCacheExpiration → set to 0, then back to 60
Safari:
└─ Develop menu → Empty Caches (or Cmd+Option+E)
All browsers:
└─ Hard refresh: Ctrl+Shift+R (Windows) / Cmd+Shift+R (macOS)
DNS Troubleshooting Checklist
DNS Cache Troubleshooting Checklist
──────────────────────────────────────────────────────────────
Step 1: Check current TTL from authoritative source
└─ dig @8.8.8.8 yourdomain.com
(bypasses local cache, queries Google's resolver)
Step 2: Check what your local resolver has cached
└─ dig yourdomain.com
(uses default resolver — shows cached TTL countdown)
Step 3: Clear OS DNS cache
└─ sudo systemd-resolve --flush-caches (Linux)
└─ ipconfig /flushdns (Windows)
Step 4: Clear browser DNS cache
└─ chrome://net-internals/#dns
Step 5: Test with different resolvers
└─ dig @1.1.1.1 yourdomain.com (Cloudflare)
└─ dig @9.9.9.9 yourdomain.com (Quad9)
Step 6: If still inconsistent — check application-level caching
└─ Does your app cache DNS independently?
└─ Restart the application or connection pool