DNS Records Explained: A, AAAA, CNAME, MX, TXT, NS — and How to Debug Them
What each record type actually does, why a CNAME can't live at your apex, why MX must never point to a CNAME, why 'DNS propagation' is mostly a myth about caching, and the dig-based debugging method that finds the real answer in five minutes instead of waiting 48 hours.
DNS Records Explained: A, AAAA, CNAME, MX, TXT, NS — and How to Debug Them
"It's always DNS" is a joke with a suspicious amount of evidence behind it. DNS sits under everything — every request, every email, every certificate issuance — and it fails in ways that look like something else: a site that's down for some users and fine for others, mail that vanishes without a bounce, a deploy that "worked" and then didn't. The system itself is simple; what bites people is the caching layer wrapped around it and a handful of rules from the 1980s that nobody mentions until they're violated.
This guide covers the record types you'll actually touch, the rules that generate real incidents, and a debugging method that finds answers in minutes instead of "waiting for propagation."
How a lookup actually works (60 seconds)
DNS does one job: it turns the names humans use (example.com) into the addresses computers connect to (203.0.113.10). When your code resolves app.example.com, the query almost never goes to the server that holds the record. The path is:
- Stub resolver (your OS) checks its cache and
/etc/hosts, then forwards the query to a configured recursive resolver — your ISP's, your router's, or a public one like1.1.1.1or8.8.8.8. - The recursive resolver checks its cache. On a miss, it walks the hierarchy: it asks a root server ("who handles
.com?"), then the.comTLD servers ("who handlesexample.com?"), then the domain's authoritative nameservers ("what's the A record forapp.example.com?"). - The answer flows back and gets cached at every layer, each cache holding it for the record's TTL.
Two consequences fall out of this, and they explain most DNS confusion:
- You're almost always talking to a cache. The answer you see is however old your resolver's copy is — which is why two people can query the same name and get different results.
- Changes don't propagate; caches expire. Nothing pushes your update to the world. The world keeps serving its cached copy until the TTL runs out, then asks again. Hold that thought — it gets its own section.
The records that matter
First, the anatomy — every DNS record, whatever its type, is one line of the same shape:
example.com. 3600 IN A 203.0.113.10
Left to right: the name the record is about, the TTL (how many seconds any cache may reuse this answer before asking again), the class (IN = internet — it's on every record; ignore it), the type (here A), and the value — the actual answer. Read the line as: "for example.com, the type-A answer is 203.0.113.10, valid for an hour." Your DNS provider's panel shows the same parts as form fields; dig shows them exactly like this. Everything below is just different record types answering different questions about a name.
| Record | Maps | Notes |
|---|---|---|
A | name → IPv4 address | The workhorse. Multiple A records = crude round-robin load balancing |
AAAA | name → IPv6 address | Same as A for IPv6; absence just means "no IPv6," not an error |
CNAME | name → another name | An alias; the query restarts with the target. Strict coexistence rules below |
MX | domain → mail server hostname | Priority + hostname; lower priority wins. Must target an A/AAAA name |
TXT | name → arbitrary text | SPF, DKIM, DMARC, domain-ownership verification. 255-byte string chunks |
NS | zone → authoritative nameservers | Delegation — who answers for this zone |
SOA | zone → zone metadata | Serial number, refresh timing, and the negative-caching TTL |
CAA | domain → permitted CAs | Which certificate authorities may issue for this domain |
PTR | IP → name | Reverse DNS; lives in the IP's zone, not yours — your hosting provider sets it |
SRV | service → host + port | Service discovery (SIP, XMPP, some Kubernetes patterns) |
A and AAAA: the terminal answers
An A record maps a name to an IPv4 address — the four-number kind. An AAAA record is the identical idea for an IPv6 address — the longer, colon-separated kind. (The name is a hint: an IPv6 address is four times the size of an IPv4 one, so it's a "quadruple-A".) These are where resolution ends: the browser takes the address and connects.
example.com. 3600 IN A 203.0.113.10
example.com. 3600 IN AAAA 2001:db8::10
A domain commonly has both, and clients that can reach IPv6 prefer the AAAA. Having no AAAA at all isn't an error — it just means "no IPv6 here," and everything keeps working over IPv4.
Multiple A records on one name are legal and common:
www.example.com. 300 IN A 203.0.113.10
www.example.com. 300 IN A 203.0.113.11
Resolvers hand back the whole set (usually in rotated order) and each client picks one — free-but-dumb load distribution. Dumb, because DNS has no health checks: if .11 dies, it keeps receiving half the traffic until you remove the record and caches expire. Real failover belongs in a load balancer or a health-checked DNS service, not in bare round-robin.
CNAME: the alias with sharp edges
A CNAME is an alias — a nickname. It says: "this name has no address of its own; it's just another name for X. Go ask about X instead."
www.example.com. 3600 IN CNAME myapp.platform.com.
myapp.platform.com. 300 IN A 203.0.113.10
When a browser visits www.example.com, four things happen: (1) the resolver asks for www.example.com; (2) the answer comes back "that's an alias for myapp.platform.com"; (3) the resolver restarts the lookup with that name; (4) it gets 203.0.113.10, and the browser connects there. Notice what you never did: type an IP address into your DNS panel. That's the point — and note that the second record above lives in the platform's zone, maintained by them, not by you.
The rule for choosing between A and CNAME: use an A record when you control the address — your own server, an IP you assigned. Use a CNAME when someone else controls the address — a hosting platform, a CDN, a SaaS product. When they renumber their servers (and they will), they update their own A records, and your zone keeps working without you touching anything. If you'd copied their IP into an A record instead, your site goes down until you notice and update it.
Two rules generate all CNAME incidents:
- A CNAME must be alone at its name. No other record — not TXT, not MX, not another CNAME — may coexist at the same name (RFC 1034; the classic operational reference is RFC 1912). Zone editors usually enforce this, but it's why "add a TXT verification record to
www" fails whenwwwis a CNAME. - Which means: no CNAME at the apex.
example.comitself must carry SOA and NS records, so it can never satisfy rule 1. This is the famous CNAME-at-apex problem, and it gets its own section below.
Also worth knowing: CNAME chains (alias → alias → alias) are legal but each hop is another lookup — keep them short — and MX or NS records pointing at a CNAME are explicitly non-compliant (RFC 2181) and break real mail servers.
MX: mail routing, three rules
MX answers one question: which server receives email for this domain? When someone sends mail to you@example.com, their mail server looks up example.com's MX records and delivers to what it finds there. Each MX record is a priority number plus a hostname:
example.com. 3600 IN MX 10 mail.example.com.
example.com. 3600 IN MX 20 backup-mail.example.com.
The lower number wins: senders try mail.example.com first and only fall back to backup-mail.example.com if the primary is unreachable. Equal priorities share the load. The rules that matter:
- The target must be a hostname with an A/AAAA record — never an IP address (syntactically invalid, though some zone editors let you save it), and never a CNAME (RFC 2181/5321; some receiving servers tolerate it, the ones that don't will teach you why the RFC exists).
- No MX at all makes senders fall back to the domain's A record — which means a web server that was never meant to receive mail may get connection attempts on port 25.
- A domain that should never receive mail should publish a null MX —
0 .(RFC 7505) — so senders fail fast instead of retrying for days.
Check any domain's MX setup — priorities, resolution, CNAME violations — with the MX lookup tool.
TXT: the junk drawer that runs email security
TXT records hold arbitrary text — DNS's public sticky notes. Anyone can read them, and that's the feature: they let a domain make publicly checkable statements about itself.
example.com. 3600 IN TXT "v=spf1 include:_spf.mailprovider.com -all"
example.com. 3600 IN TXT "google-site-verification=abc123def456"
Over the years those statements have accreted into critical infrastructure — above all the email-security trio:
- SPF (a TXT at the apex, starting
v=spf1) lists which servers are allowed to send email claiming to be from your domain. - DKIM (a TXT at
selector._domainkey.example.com) publishes the public key that lets receivers verify the cryptographic signature your mail server adds to every outgoing message. - DMARC (a TXT at
_dmarc.example.com) tells receivers what to do when those two checks fail — deliver anyway, quarantine, or reject — and where to send you reports about it.
Plus every SaaS product's verification=abc123 proof that you own the domain. And unlike a CNAME, a name can carry as many TXT records as it needs — the two records above coexist happily; the one-per-name rule below is specific to SPF.
Two mechanical gotchas:
- A single TXT string maxes out at 255 bytes. Longer values — DKIM keys, chiefly — are split into multiple quoted strings inside one record (
"part1" "part2"), which readers concatenate. Most providers split automatically; pasting a 2048-bit DKIM key into a provider that doesn't will silently truncate it. - Exactly one SPF record may exist. Two
v=spf1TXT records at the same name is apermerror— evaluators treat it as no valid SPF at all. This happens constantly when a second email service's setup guide says "add our SPF record" and someone does, instead of merging theinclude:into the existing one.
The email trio has deep behavior beyond the DNS mechanics — alignment, policy ramp-up, reporting. That's covered in the email deliverability pillar; for quick checks, the SPF checker, DKIM checker, and DMARC generator handle the record-level work.
NS and delegation: who answers for you
Somewhere, real servers have to hold your records and answer queries about them. Those are your nameservers — usually your DNS provider's (ada.ns.cloudflare.com, ns1.yourhost.com) — and NS records publish which ones speak for your domain:
example.com. 172800 IN NS ns1.dnsprovider.com.
example.com. 172800 IN NS ns2.dnsprovider.com.
Switch DNS providers and these are the records that change (at your registrar). The subtlety that causes incidents: NS records exist in two places — in the parent zone (the .com servers hold NS records delegating example.com to your provider) and in your own zone. The parent's copy is what the world follows; your zone's copy is what you assert. After a DNS-provider migration these can disagree — you updated the registrar but an old NS set lingers in one zone, or vice versa — and the symptom is the worst kind: intermittent. Some resolvers follow the old delegation, some the new, and the site "works for me, not for them" for days.
Related concepts worth having filed away: glue records (when a nameserver's own name lives inside the zone it serves — ns1.example.com serving example.com — the parent must carry its IP, or resolution deadlocks), and lame delegation (an NS record pointing at a server that doesn't actually answer for the zone).
SOA, CAA, PTR: the three you'll meet eventually
- SOA carries zone metadata; the field that affects you is the minimum/negative TTL — how long resolvers cache "this name doesn't exist." Query a record before creating it and that NXDOMAIN gets cached; the record then "doesn't work" for you (and only you) until the negative cache expires.
- CAA whitelists which certificate authorities may issue for your domain. A forgotten CAA record from a previous CA is a classic cause of Let's Encrypt issuance failures — if certificate renewal breaks after a DNS migration, check CAA before anything else, and check the served certificate with the SSL certificate checker.
- PTR maps an IP back to a name. It lives in the IP owner's zone (
in-addr.arpa), so you configure it in your hosting provider's panel, not your DNS zone. Mail servers without matching forward/reverse DNS get their mail rejected — it's a standard spam heuristic. The IP address lookup and ASN/WHOIS lookup tell you who actually controls an address block when you need the PTR changed.
TTL strategy: the contract you're signing
Every record carries a TTL — the number of seconds any cache may serve the answer without re-asking. It's the single knob that controls how fast your changes take effect, and it works backwards in time: the TTL that governs your migration is the one that was on the record before you changed it.
The playbook for any planned change:
- At least one old-TTL before the change, lower the TTL (e.g. 86400 → 300). You have to wait out the old TTL for the new, shorter one to be in every cache.
- Make the change. The world now converges within ~5 minutes.
- Verify, then raise the TTL back once you're confident you won't roll back.
For steady-state values: 3600 (an hour) is a sensible default for stable records; 300 for anything involved in failover or frequent cutover; 86400 for records that change yearly. Permanently running 30–60s TTLs on everything buys nothing except higher latency for your users (more cold lookups) and total dependence on your DNS provider's uptime — and some large resolvers clamp tiny TTLs upward anyway, so sub-minute failover schemes are partly theater.
The CNAME-at-apex problem, and the workarounds
You're deploying to a platform that says "point your domain at yourapp.platform.com." For www.example.com, easy — a CNAME. For example.com itself, impossible: the apex holds SOA and NS records, and a CNAME tolerates no neighbors.
Three real options:
- ALIAS / ANAME / CNAME flattening. Your DNS provider resolves
yourapp.platform.comitself, server-side, and serves the resulting addresses as synthesized A/AAAA records. Cloudflare flattens automatically; Route 53 has ALIAS; most modern providers have an equivalent. This is the right answer when available — behaviorally a CNAME, protocol-legal at the apex. The tradeoff: the flattening resolver's vantage point picks the IPs, which can defeat some geo-routing. - Static A/AAAA records at the apex. Some platforms publish stable apex IPs for exactly this. Fine, with the obvious coupling: if the platform renumbers, your zone is stale.
- HTTP-level redirect. Serve a 301 from
example.comtowww.example.comand do the CNAME onwww. Old-school, utterly reliable, and it concentrates your DNS flexibility on one subdomain.
"Propagation" is mostly a myth
The phrase "waiting for DNS to propagate" implies your change is traveling outward through the internet. It isn't. Authoritative servers answer with the new value as soon as the zone is published — usually seconds. Everything after that is cache expiry, on a schedule the old TTL already fixed.
So when a change "hasn't propagated," decompose it:
- The authoritative servers — do they serve the new value?
dig @ns1.yourprovider.com example.com A. If not, the change didn't actually publish; no waiting will fix it. - Your recursive resolver — is it still serving its cached copy? Compare
dig example.com Aagainst the authoritative answer. Thedigoutput's TTL column shows the cache's remaining seconds, counting down. - Your own machine — the OS caches lookups, and browsers keep their own DNS cache on top of that. Flush the OS cache with
ipconfig /flushdns(Windows),sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder(macOS), orresolvectl flush-caches(Linux with systemd-resolved); restart the browser rather than fighting its internal cache. And check/etc/hosts— a forgotten override from last month's debugging session beats DNS every time, silently. - Negative caching — if you queried the name before creating the record, the NXDOMAIN is cached for the SOA-minimum duration. This is the one that makes brand-new records "not work" for exactly the person who set them up.
The genuine multi-hour cases are nameserver changes: the delegation NS records at the TLD often carry 48-hour TTLs you don't control. That — and only that — is where the "24–48 hours" folklore is earned. For everything else, a clean-vantage-point DNS lookup that queries all record types without your local cache in the way settles "is it live?" in one check.
Debugging DNS with dig: the method
The failure mode in DNS debugging is checking from one place, seeing a stale or local answer, and "fixing" a record that was already right. The method that avoids it: authoritative first, then delegation, then caches.
# What does the world's cache say? (your resolver)
dig example.com A
dig example.com MX +short
dig example.com TXT
# What does the source of truth say? (bypasses ALL caches)
dig example.com NS +short
dig @ns1.provider.com example.com A
# Walk the whole delegation chain: root → TLD → authoritative
dig example.com A +trace
# Ask specific public resolvers (is it just MY resolver?)
dig @8.8.8.8 example.com A
dig @1.1.1.1 example.com A
# Reverse DNS
dig -x 203.0.113.7
# DNSSEC check: does disabling validation fix a SERVFAIL?
dig example.com A +cd
How to read the three answers you'll get:
- NXDOMAIN — the name doesn't exist, no records of any type. Cached negatively per the SOA minimum.
- NOERROR, empty answer — the name exists, but not the record type you asked for. Not an error; asking for AAAA on an IPv4-only host looks exactly like this.
- SERVFAIL — the resolver couldn't produce a validated answer. The modern number-one cause is broken DNSSEC. (DNSSEC in one breath, for anyone meeting it here: an extension that adds cryptographic signatures to DNS records, so resolvers can verify an answer really came from the domain's owner and wasn't forged in transit. The signatures expire and must be re-signed continuously, and the chain of trust is anchored by a DS record held at your registrar.) The two classic breakages: signatures that expired because re-signing stopped, and a stale DS record left at the registrar after switching DNS providers. The symptom is diabolical — validating resolvers (8.8.8.8, 1.1.1.1) fail while non-validating ones answer fine, so the outage hits "some users" and every test on the wrong resolver says everything's healthy.
dig +cd(checking disabled) succeeding where the plain query fails is the confirmation.
And the classic zone-file bug, for anyone editing raw zones: names without a trailing dot are relative to the zone, so writing mail.example.com instead of mail.example.com. as an MX target creates mail.example.com.example.com. If dig ever shows you a doubled domain, that's the trailing dot.
One last check for when every DNS answer looks right but the browser still lands on the old server — the remaining suspects aren't DNS at all. Browsers cache 301 redirects aggressively, and a CDN may still point at the old origin. Force a connection to the new address and see what the server itself says:
curl --resolve example.com:443:203.0.113.10 https://example.com/
If that returns the new site, DNS and the server are fine — go clear the redirect or fix the CDN origin.
The gotcha checklist
The incidents in this article, compressed for future greps:
- CNAME coexisting with other records — illegal; blocks TXT verification at CNAME'd names; forbids apex CNAMEs.
- MX pointing at a CNAME or a bare IP — non-compliant; some mail servers refuse it.
- Two SPF records —
permerror, evaluated as no SPF at all. Merge theinclude:s. - TTL lowered after the migration — the old TTL governs; lower it one old-TTL in advance.
- Querying a record before creating it — negative caching makes it invisible to you specifically.
- Parent/child NS mismatch after provider migration — intermittent, resolver-dependent breakage.
- SERVFAIL on validating resolvers only — DNSSEC; usually a stale DS record after changing DNS providers.
- Stale CAA record — silent certificate-issuance failures at renewal time.
- Missing trailing dot in a zone file —
mail.example.com.example.com. - Round-robin A records as "failover" — DNS has no health checks; dead IPs keep their share of traffic.
The short version
DNS is a distributed cache with a write-once-read-everywhere pattern, and every mystery reduces to the same question: which server gave you that answer, and how old is it? Query the authoritative server first — a full-record DNS lookup or dig @ns1... — and you know in one step whether you're debugging your zone or someone's cache. Lower TTLs before changes, not after. Respect the three coexistence rules (CNAME alone, MX to a hostname, one SPF). And when a resolver says SERVFAIL while another answers fine, it's DNSSEC — it's always DNSSEC. Except when it's the trailing dot.