Back to guides
Basics

DNS Caching & TTL

Almost every DNS answer is reused rather than looked up fresh, which is why the web feels instant. The rule that decides how long an answer may be reused is the TTL, a small number attached to every record. Understand TTL and most DNS surprises stop being surprising.

By Ozy-666, creator and operator of dnsdoh.art · Published · 6 min read
Your device Authoritative CACHE example.com → 203.0.113.42 TTL served from cache expired · refetching

While the TTL bar has time left, repeat lookups are answered instantly from the cache. When it hits zero, the next lookup fetches a fresh copy and the timer resets to full.

Two ideas do all the work here: a cache stores answers so they can be reused, and a TTL says how long each one may be reused before it has to be fetched again.

Why caching exists

Looking up a name from scratch means walking the hierarchy, as how DNS actually works and the guide on what a DNS resolver is describe: root, then the top-level domain, then the domain's own server. That is fast, but doing it for every single request, including the dozens of names a single web page pulls in, would be wasteful and slow.

So every layer keeps a cache. Your browser caches, your operating system caches, and the resolver caches most of all. The first lookup for a name does the full walk; for a while after that, the same answer is handed back instantly without leaving the machine. Caching is the difference between DNS you notice and DNS you do not. Which cache does the work on a given resolver is worth knowing: on this one it is Unbound, with prefetching, as the server infrastructure and transparency report sets out.

What TTL actually is

TTL stands for “time to live,” and it is simply a number of seconds attached to every DNS record by whoever owns the domain. It is best read as a permission slip: you may reuse this answer for this many seconds. A record with a TTL of 3600 may be served from cache for an hour; after that, the cache must throw it away and ask again.

Every cache along the path obeys the same number, counting it down independently from the moment it received the answer. That is the whole mechanism. The art is only in choosing the number.

What the numbers mean

TTLRoughlyWhat it is for
0never cacheAlways fetch fresh. Used for names that must not be reused, such as the one-time names a leak test generates, or records mid-change.
601 minuteFast failover, load balancing, dynamic DNS. Changes spread within a minute, at the cost of far more lookups.
3005 minutesA safe, agile default for records you might change soon. Quick to update without hammering the servers.
36001 hourThe common default for stable records like a site's address. Reused for an hour, light on lookups.
864001 dayRecords that almost never change, such as nameserver records. Minimal traffic, slow to alter.

There is no single correct value; every choice is a trade, and the next section is that trade.

The trade-off, and the classic trick

A low TTL means changes take effect quickly, because caches forget the old answer soon, but it also means many more lookups, since the answer expires constantly. A high TTL is the opposite: very few lookups and snappy responses, but a change can take up to the full TTL to reach everyone.

This is why administrators use a well-known move before changing an important record: lower its TTL a day or two ahead of time, say from 3600 down to 300, so that when the change goes live the old answer drains out of caches within minutes instead of an hour. Once the change has settled, the TTL is raised again. You plan the agility in advance, because you cannot add it retroactively.

Why DNS changes feel slow

When you update a record and it does not seem to take effect, nothing is broken and nothing is “propagating” in the sense people imagine. What is really happening is that caches around the world are still holding the old answer until their own copy of the TTL counts down. There is no central switch and no way to reach into every cache and force it to forget.

So the time a change takes to spread is, at most, the TTL the record had before you changed it. That old value is the one still ticking down in everyone's cache. The new low TTL only helps for the next change.

Negative caching

“No such name” is an answer too, and it gets cached with its own TTL. That is why a typo'd or just-created domain can keep returning “not found” for a short while even after it exists: the negative answer is still live in the cache.

Serving stale on purpose

Some resolvers bend the rule for speed: when a record just expired, they hand back the old answer in milliseconds and refresh it in the background. This serve-expired behaviour is part of the resolver setup here, trading a moment of staleness for a never-slow response.

See it for yourself

A caching resolver shows you the TTL counting down. Ask repeatedly and watch it fall, hit zero, and jump back to full when the next query fetches a fresh copy. api.github.com is a good subject because GitHub publishes a 60-second TTL, so a whole cycle fits in a minute:

$ dig @1.1.1.1 api.github.com A +noall +answer   # repeated
api.github.com.   7    IN   A   140.82.121.5
api.github.com.   1    IN   A   140.82.121.5
api.github.com.   44   IN   A   140.82.121.5   # refetched, counting from 60
api.github.com.   11   IN   A   140.82.121.6   # and the address moved

The second column is the seconds remaining. The last line is the reason a short TTL is worth its cost: the address changed between two lookups a minute apart, and every cache in the world picked that up within 60 seconds because that is what GitHub told them to do.

The number you are shown is not always the number that was published

That is the part most explanations leave out, and it is easy to check. A resolver is free to rewrite the TTL it hands you, and most do at both ends of the scale. Ask a domain's own nameserver, then ask this resolver:

$ dig @ns-1707.awsdns-21.co.uk api.github.com A   # the source
api.github.com.   60     IN   A    140.82.121.5

$ dig @194.180.189.33 api.github.com A            # this resolver
api.github.com.   300    IN   A    4.225.11.201

$ dig @1.1.1.1 iana.org NS                        # published: 86400
iana.org.         86400  IN   NS   a.iana-servers.net.

$ dig @194.180.189.33 iana.org NS
iana.org.         3600   IN   NS   c.iana-servers.net.

Both numbers were changed on the way through, in opposite directions. Sixty seconds became 300, because the cache behind this resolver refuses to store anything for less than five minutes - a floor. A day became 3600, because the filtering layer in front of it caps every answer at an hour - a ceiling. Neither is unusual; public resolvers do the same thing with their own numbers.

The floor buys fewer upstream lookups, which is both faster and quieter: a name asked for constantly leaves this network twelve times an hour instead of sixty. The cost is that a change made by the domain owner can take five minutes to be seen here rather than one. The ceiling works the other way, making clients re-ask about long-lived records more often than the owner asked for, which keeps a stale delegation from lingering for a day.

This is worth knowing before the standard migration advice, which is to lower a record's TTL a day before moving it. That advice assumes every cache honours your small number. Some will floor it, so plan for the floor rather than the number you published, and verify against the resolvers your users actually use rather than against your own nameserver.

It is all one dial

Fast to change, or light on lookups. TTL is just where you set that dial, per record.

Browse the guides