The path of one DNS lookup in brief
A DNS lookup first checks caches on your own device. If none has the answer, a recursive resolver finds it by asking a root server, then the top-level domain's servers, then the domain's authoritative nameservers. It caches what it learns and returns the answer to your device.
Many lookups end early, because a cache along the way already holds the answer or part of the path to it. The full walk only happens when nothing useful is cached.
Step 1: the browser and operating system check their caches
When you open www.example.com, the browser checks its own DNS cache first. On a miss, it asks the operating system, whose stub resolver checks the hosts file and its own cache.
If that misses too, the stub resolver sends a recursive query to the resolver your network or settings point to. A recursive query asks for a complete answer, so the stub does no searching of its own.
A home router often sits in between as a caching forwarder, passing queries on to your ISP's resolver or a public one.
Step 2: the recursive resolver checks what it already knows
The recursive resolver looks for the exact record in its cache first. If it holds an unexpired copy, it answers immediately.
Otherwise it starts from the closest delegation it has cached. A resolver that already knows the nameservers for example.com goes straight to them, and one that only knows the .com servers starts there. Only a resolver with nothing relevant cached starts at the root.
From here the resolver sends iterative queries. Each server it asks either answers or replies with a referral, which names the nameservers for the next zone down.
Steps 3 to 5: root, TLD and authoritative nameservers
Starting from the root, the walk for www.example.com takes three hops. Many resolvers use query name minimization (RFC 9156) along the way, telling each upper-level server only the part of the name it needs.
- A root server replies with a referral to the .com nameservers. There are 13 root server names, a.root-servers.net to m.root-servers.net, each served from many sites through anycast, and resolvers ship with their addresses as root hints.
- A .com server replies with another referral: the NS records for example.com, which the registry publishes from the nameservers you set at your registrar. When those nameservers sit inside the domain itself, the referral also carries their addresses as glue records.
- One of the authoritative nameservers for example.com returns the record itself, with the AA (authoritative answer) flag set. If the answer is a CNAME, the resolver follows it to the target name, which can mean another walk.
Step 6: caching the answer, and caching "no such name"
The resolver returns the answer to your stub resolver and caches every record it collected, each for its own TTL. That includes the referrals, so its next lookup for any .com name can skip the root.
Failed lookups are cached too. NXDOMAIN means the name does not exist, and NODATA means it exists but has no record of that type. Under RFC 2308, both are cached for the lower of the SOA record's TTL and the minimum field inside it.
Negative caching is why looking up a name before you create it can make the new record seem slow to appear.
Watching a lookup with dig +trace
The +trace option of the dig command performs the same walk from your own machine. It asks your resolver only for the list of root servers, then queries the root, TLD and authoritative servers itself and prints each referral.
Because it bypasses your resolver's cache, +trace shows what the delegation chain says right now. Compare it with a plain dig query to your resolver to tell a delegation problem from a caching one.
Each block of output is one hop: the records a server returned, followed by a line naming the server that sent them. The last block is the answer from the domain's own nameserver.
$ dig +trace www.example.com
# Abbreviated output. Server names, addresses and timings are examples.
. 518400 IN NS a.root-servers.net.
;; Received 239 bytes from 192.168.1.1#53(192.168.1.1) in 4 ms
com. 172800 IN NS a.gtld-servers.net.
;; Received 1170 bytes from 198.41.0.4#53(a.root-servers.net) in 20 ms
example.com. 172800 IN NS ns1.example.net.
;; Received 650 bytes from 192.5.6.30#53(a.gtld-servers.net) in 28 ms
www.example.com. 3600 IN A 192.0.2.10
;; Received 60 bytes from 192.0.2.53#53(ns1.example.net) in 24 ms