DNS records explained for developers
A, AAAA, CNAME, MX, TXT, NS, and how to verify them before a deployment — including TTL, propagation, and the apex-CNAME trap.
Why DNS deserves a pre-flight check
Most outages caused by DNS are not DNS being slow or unreliable — they are records that were typed wrong, partially updated, or never propagated. A 30-second `dig` before pointing customers at a new domain catches the vast majority of these.
The records below are the ones developers actually touch. Knowing what each does, how to read it, and how to verify it from outside your own resolver is the whole skill.
A and AAAA: address records
A records map a hostname to one or more IPv4 addresses. AAAA does the same for IPv6. Multiple A records for the same name is round-robin DNS — clients pick one per lookup.
When your service supports dual stack, ship A and AAAA together. Shipping AAAA before your servers are IPv6-ready breaks clients that prefer IPv6 (most modern OSes).
dig A example.com +short
dig AAAA example.com +short
# Specify a public resolver to bypass your local cache:
dig @1.1.1.1 A example.com
dig @8.8.8.8 AAAA example.com CNAME and the apex domain trap
CNAME aliases one hostname to another. Common for CDN endpoints (`www.example.com → d12345.cloudfront.net`), SaaS integrations, and certificate verification subdomains.
Critical rule: the apex (root) of a domain — like `example.com` itself — cannot legally have a CNAME alongside the SOA and NS records that must live there. Providers solve this with non-standard "ALIAS", "ANAME", or "CNAME flattening" features that look like CNAME but resolve to A/AAAA at query time. If your DNS host does not support these, use A records at the apex.
dig CNAME www.example.com
# This usually returns no CNAME, only A/AAAA:
dig CNAME example.com MX records and email routing
MX records say which servers receive mail for a domain. Each MX has a priority — lower number = higher priority. Clients try lowest first, fall back to higher numbers.
When migrating mail, watch the priorities. Leaving the old MX at priority 10 and adding new at priority 20 means new servers only see traffic when the old ones fail — which is rarely what migration means.
dig MX example.com +short
# Returns lines like:
# 10 mail1.example.com.
# 20 mail2.example.com. TXT records: SPF, DKIM, DMARC, and verification
TXT records hold arbitrary strings. In practice that means: SPF (which servers may send mail as your domain), DKIM (public keys for mail signing), DMARC (what receivers should do with failures), and short verification tokens from services like Google Workspace, GitHub Pages, or AWS ACM.
A domain can have many TXT records — they are not exclusive. Long values get split into multiple quoted chunks at the wire level but represent one logical value. Most tools concatenate them for you.
dig TXT example.com +short
# Filter for a single mechanism:
dig TXT example.com +short | grep "v=spf1"
dig TXT _dmarc.example.com +short NS records and delegation
NS records list the authoritative name servers for a zone. The registrar holds the NS records at the parent (the TLD), and the zone itself should publish matching NS records — they must agree.
When you delegate a subdomain (e.g., handing `apps.example.com` to a different provider), you set NS records for that subdomain in the parent zone. Mismatches between parent NS and child NS are a classic source of "works for some users, fails for others" bugs.
dig NS example.com +short
# See what the TLD actually delegates (whois-style):
dig NS example.com @a.iana-servers.net TTL, propagation, and verification
Every record has a TTL — how long resolvers may cache the answer. Lower TTL before a planned change (a day in advance) so the cutover propagates fast. Raise it back after the change settles.
"DNS propagation" is really "cache expiration". A change is visible immediately at authoritative servers; it appears worldwide only as cached entries expire. Always verify from multiple public resolvers, not just your own machine.
# Check from several resolvers:
for R in 1.1.1.1 8.8.8.8 9.9.9.9 208.67.222.222; do
echo -n "$R: "
dig @$R A example.com +short
done
# See the current TTL value:
dig A example.com