CNAME Flattening Explained
CNAME flattening lets authoritative nameservers serve CNAME-like behavior at the zone apex by resolving the alias target server-side and returning synthesized A/AAAA records, so you can point example.com (not just www.example.com) at a CDN or load balancer without breaking the DNS wire protocol.
The technique sidesteps the RFC 1034/1035 rule that forbids a CNAME at the zone root. That rule exists because the apex label must already carry mandatory SOA and NS records, and a CNAME is defined to be the only record that can exist at a name. A literal apex CNAME would therefore collide with the records that make the zone authoritative at all. Flattening solves the conflict by moving the indirection off the wire: the client never sees a CNAME, only the final addresses. Understanding how this interacts with the rest of DNS Fundamentals & Advanced Record Configuration is essential for running apex domains against modern edge platforms with zero downtime.
Key implementation points:
- Bypasses the RFC restriction on apex CNAMEs without ever putting a CNAME on the wire.
- The authoritative server performs the target resolution and returns synthesized A/AAAA records.
- Removes one client-side lookup round trip, which matters for first-byte latency on apex traffic.
- Requires TTL alignment between your zone and the target so clients do not cache decommissioned CDN IPs.
How CNAME Flattening Works
A standard CNAME is an indirection record: it says “this name is an alias for that name, go look it up.” A recursive resolver that receives a CNAME has to issue at least one more query to chase the target before it can hand an address back to the application. That is fine for www and other sub-domains, but it is forbidden at the apex.
The apex (the bare registrable domain such as example.com) is special because it must carry the SOA record that defines the zone and the NS records that delegate it. RFC 1034 §3.6.2 states that a CNAME must be the only data associated with a name. Since the apex already has SOA and NS data, a CNAME there is a contradiction, and conformant authoritative servers will refuse to load such a zone. This is not a vendor limitation you can configure away — it is baked into how delegation works.
Flattening resolves the contradiction by relocating the indirection from the client side to the authoritative server. You still configure a CNAME-style target at the apex, but the server treats it as an instruction rather than a record to publish. When a query for example.com A arrives, the authoritative server resolves the configured target hostname itself, takes the resulting addresses, and returns them as A/AAAA records owned by the apex name. The client and its recursive resolver only ever see addresses. This is why flattening is sometimes described as “synthesized” addressing, and it is closely related to the record-type model covered in Understanding DNS Record Types.
Resolution chain (flattened apex):
- Client resolver queries
example.com A. - The authoritative nameserver detects the apex-CNAME (flattening) configuration for that name.
- The server recursively resolves the configured target hostname (for example
app.cdn-provider.net). - The server synthesizes A/AAAA records from the target’s current addresses.
- The server returns those addresses directly, with the apex name as owner. No CNAME appears in the answer.
The trade-off versus a literal CNAME chain is that the resolution work moves to your DNS provider and runs on their cache, not the client’s. Whether that cache is refreshed per-query (real-time flattening) or on a background interval determines how quickly target IP changes reach users — the central operational concern of the rest of this guide.
It is worth being precise about where the indirection disappears. With a normal sub-domain CNAME, every recursive resolver on the internet independently chases the chain, so the cost is paid once per resolver cache miss across the whole population. With flattening, the chase happens inside your authoritative provider, typically against a warm cache shared by all of their edge nodes. The result is fewer aggregate upstream lookups and a smaller, more predictable answer that the client can act on immediately. The downside is a loss of transparency: because the client never sees the target hostname, you cannot debug an apex problem purely from the client side — you have to query the authoritative server directly, which is why every verification step in this guide pins dig to a specific @ns host.
Provider-Specific Implementation
Major DNS platforms implement apex routing differently, and the differences matter: some perform true server-side flattening, some use a proprietary ALIAS/ANAME record type that achieves the same outcome, and some only flatten under specific conditions. Always verify that the target record set is published and propagated before you enable flattening, or the first synthesized response can be an empty answer or an NXDOMAIN that resolvers will then cache.
Cloudflare
Cloudflare performs genuine server-side flattening and exposes two modes: flatten_at_root (apex only, the default) and flatten_all (every CNAME in the zone). You configure it by creating a record of type CNAME at @. With proxied: false the platform flattens silently at the DNS layer, returning the target’s A/AAAA records for the apex. With proxied: true the apex is additionally fronted by Cloudflare’s edge, the published TTL is forced to 1 (auto), and you gain the option to run logic in front of the origin — see Cloudflare Workers Routing for what that edge layer can do.
{
"type": "CNAME",
"name": "@",
"content": "app.cdn-provider.net",
"proxied": false,
"ttl": 300
}
To set the zone-wide policy with the API:
curl -s -X PATCH \
"https://api.cloudflare.com/client/v4/zones/$ZONE_ID/settings/cname_flattening" \
-H "Authorization: Bearer $CF_TOKEN" \
-H "Content-Type: application/json" \
--data '{"value":"flatten_at_root"}'
With proxied: false, Cloudflare resolves app.cdn-provider.net internally and returns the resulting A/AAAA records for @. With proxied: true, traffic passes through Cloudflare’s network and the wire TTL is 1.
AWS Route 53
Route 53 does not flatten a CNAME; it provides a proprietary ALIAS record that yields the same wire result. You create an A (or AAAA) record with an AliasTarget, and Route 53 answers queries with the alias target’s current addresses. Setting EvaluateTargetHealth: true ties the answer to the target’s health checks so unhealthy endpoints are withdrawn automatically.
{
"Name": "example.com.",
"Type": "A",
"AliasTarget": {
"HostedZoneId": "Z2FDTNDATAQYW2",
"DNSName": "d-1234567890.execute-api.us-east-1.amazonaws.com.",
"EvaluateTargetHealth": true
}
}
Apply it idempotently with the CLI:
aws route53 change-resource-record-sets \
--hosted-zone-id Z3AADJGX6KTTL2 \
--change-batch file://apex-alias.json
ALIAS records are free of query charges within Route 53 when the target is an AWS resource, and they do not consume an extra resolution hop for the client.
Azure DNS and Google Cloud DNS / Fastly
Azure DNS implements an alias record set: you create an A/AAAA alias whose target is an Azure resource (commonly a Traffic Manager profile or a CDN endpoint), and Azure returns the resolved addresses. Failover and geo-steering are delegated to Traffic Manager rather than to DNS itself.
az network dns record-set a create \
--resource-group rg-dns --zone-name example.com --name "@" \
--target-resource "/subscriptions/<sub>/resourceGroups/rg-net/providers/Microsoft.Network/trafficManagerProfiles/tm-prod"
Google Cloud DNS does not support a flattened apex CNAME natively; the supported pattern is to front the apex with a Google Cloud Load Balancer and publish its static anycast IP as a plain A record, or to use a third-party DNS provider for flattening. Fastly’s hosted DNS and many managed providers (NS1, DNSimple, DNS Made Easy) expose this as an ANAME/ALIAS record that flattens at query time. The practical lesson across vendors: confirm whether your provider flattens per query or on a refresh interval, because that governs propagation latency.
Platform Comparison
| Provider | Mechanism | Wire record type | Failover / Notes |
|---|---|---|---|
| Cloudflare | Server-side CNAME flattening (real-time) | A/AAAA | Yes — via proxy health or target’s own records; proxied:true forces TTL 1 |
| AWS Route 53 | Proprietary ALIAS record | A/AAAA | Yes — EvaluateTargetHealth; no extra query charge for AWS targets |
| Azure DNS | Alias record set | A/AAAA | Yes — delegated to Traffic Manager profile |
| Google Cloud DNS | No native apex flatten; use LB static IP | A (plain) | Via load balancer; not a DNS-layer mechanism |
| Fastly / NS1 / DNSimple | ANAME / ALIAS at query time | A/AAAA (synthesized) | Yes — provider re-resolves target on its refresh interval |
Rollback protocol:
- Keep a parallel
wwworfallbackA record pointing at a static, known-good origin you control. - If flattening starts returning stale or empty answers, lower the apex TTL to 60s and wait one TTL window.
- Switch the apex from the flattened/ALIAS record to a direct A record with a known-good IP.
- Purge the provider’s authoritative cache via API so the change is not masked by their own caching layer.
- Re-enable flattening only after the target’s health checks pass consistently for several cycles.
TTL Management & Caching Implications
Flattening introduces a second TTL into the picture, and getting them aligned is the single most common operational mistake. A flattened response carries a TTL, but that TTL is effectively bounded by the minimum of your apex configuration’s TTL and the TTL on the target’s A/AAAA records, because the authoritative server cannot safely serve a synthesized address longer than the upstream record claims to be valid. If your CDN publishes its addresses with a 300-second TTL, recursive resolvers will hold the flattened IPs for up to 300 seconds regardless of what you set on the apex.
This is where alignment with Mastering TTL Strategies pays off. In dynamic environments where the CDN rotates addresses, you want short TTLs on the target records (which you usually do not control) and you want a provider that re-resolves the target frequently. When the provider caches the target resolution on a long interval, a CDN IP change can be invisible to your zone until that interval lapses — even if the client-facing TTL looks short.
Caching considerations:
- Some recursive resolvers honor the authoritative TTL exactly; others clamp it to a local minimum or maximum, so observed cache lifetime varies by resolver.
- Wire up health checks that trigger a provider cache purge on detected IP changes rather than relying on TTL expiry alone.
- Prefer providers that flatten in real time (re-resolving the target at query time) for geo-distributed CDNs where addresses differ by location.
- Test TTL behavior across
1.1.1.1,8.8.8.8, and9.9.9.9to catch resolver-specific overrides before they surprise you during an incident. - If the CDN uses EDNS Client Subnet (ECS) for geo steering, the flattening server must forward ECS upstream, or every client gets the same synthesized address regardless of location.
Apex flattening also intersects with how you operate the rest of the zone. When you migrate providers or restructure records, treat the flattened apex as a first-class object in your runbook — the procedures in DNS Zone Management for staged cutover and parallel-serving apply directly, because a misordered change at the apex takes the bare domain offline for everyone.
A subtle caching pitfall is negative caching. If a query for the apex ever returns NXDOMAIN or an empty answer — for instance because you enabled flattening seconds before the target was reachable — resolvers cache that negative result for the duration of the zone’s SOA minimum TTL (the last field of the SOA record). Lowering the SOA minimum before a risky apex change shrinks how long a bad negative answer can linger. This is the inverse of the positive-TTL concern: with positive answers you worry about stale-but-present IPs, while with negative answers you worry about a cached “does not exist” surviving long after the real record is healthy.
Numbered Configuration Procedure
The following procedure moves an apex from a static A record onto a flattened CDN target with no downtime window.
- Publish the target first. Confirm the CDN/load balancer hostname (
app.cdn-provider.net) resolves to healthy addresses:dig +short app.cdn-provider.net A. Do nothing else until this returns real IPs. - Lower the current apex TTL. Drop the existing apex A record to 60s and wait one full previous-TTL window so resolvers expire the old value. This shrinks your rollback blast radius.
- Stage the flattening record. Create the apex CNAME/ALIAS pointing at the target, but if your provider supports a preview or a low-traffic test record, validate it there first (for example a
flat-testlabel aliased to the same target). - Verify synthesis at the authoritative server. Query the provider’s nameserver directly (see the
dig @nscommand below) and confirm the answer is A/AAAA with no CNAME and a sane address set. - Cut the apex over. Replace the apex A record with the flattening record. Watch real-user metrics and authoritative query logs for NXDOMAIN or SERVFAIL spikes.
- Restore a production TTL. Once stable, raise the apex TTL to your normal value (commonly 300–3600s) to reduce query load, keeping it short enough that an emergency change still propagates quickly.
- Document the rollback. Record the known-good fallback IP and the purge API call in the runbook so any on-call engineer can revert in minutes.
Debugging & Verification
Use dig against the authoritative nameserver to isolate the synthesized answer from recursive-resolver caches. The goal is to confirm the response contains direct A/AAAA records and no CNAME chain.
dig @ns1.cloudflare.com example.com A +noall +answer
Expected output:
example.com. 300 IN A 104.26.10.123
example.com. 300 IN A 172.67.145.89
Trace the full delegation to prove there is no CNAME hiding at the apex:
dig +trace example.com A | grep -iE "CNAME|IN.A"
If a CNAME appears in either answer section, flattening is not configured or is not operating — the resolver is seeing indirection it should never see at the apex.
Check DNSSEC alongside flattening. Because the server synthesizes the A/AAAA set at (or near) query time, it must also produce a valid RRSIG covering that synthesized set. A statically pre-signed (offline) zone cannot do this and will fail validation:
dig @ns1.cloudflare.com example.com A +dnssec +multiline | grep -i rrsig
For the deeper architectural trade-offs between true server-side flattening and proprietary ALIAS records — including how each behaves under DNSSEC and multi-provider setups — see CNAME flattening vs ALIAS records at the apex domain.
Verification checklist:
- [ ] Authoritative answer contains only A/AAAA records (no CNAME chain).
- [ ]
+traceoutput shows no CNAME at the apex label. - [ ] DNSSEC
rrsigcovers the synthesized address set and validates. - [ ] Recursive-resolver TTL matches the authoritative minimum across
1.1.1.1,8.8.8.8, and9.9.9.9. - [ ] ECS forwarding confirmed if the target does geo-IP steering.
Troubleshooting & Rollback
| Symptom | Likely cause | Action |
|---|---|---|
| Apex returns NXDOMAIN intermittently | Flattening enabled before the target published records; provider cached the empty answer | Confirm target resolves, then purge provider cache; lower TTL during recovery |
| Clients reach a decommissioned node | Stale synthesized IPs held past target TTL | Shorten target A-record TTL; trigger purge on IP change; verify provider re-resolves in real time |
| SERVFAIL on DNSSEC-validating resolvers | Synthesized set not signed at query time | Use a provider that signs synthesized records online; do not pre-sign offline |
| Geo routing collapses to one region | ECS not forwarded during internal resolution | Switch to a provider that forwards ECS, or front the apex with the CDN’s own anycast IP |
| Apex TTL “stuck” longer than configured | Resolver clamps TTL, or provider caches target resolution on a long interval | Test across multiple resolvers; pick a provider with short target-refresh intervals |
If any of these escalate to an outage, execute the five-step rollback protocol above: lower TTL, swap to a static A record at a known-good IP, purge the authoritative cache, and only re-enable flattening once health checks are green.
Edge Cases & Gotchas
- DNSSEC requires online signing. Flattening changes the record set, so a pre-signed offline zone will fail validation. Confirm your provider signs synthesized records at query time before enabling DNSSEC on a flattened apex.
- Target TTL wins. You cannot make a flattened record live longer than its upstream target claims; plan TTL around the value you do not control.
- ECS is opt-in. Geo-aware CDNs need the flattening server to forward EDNS Client Subnet, or all users collapse onto one address set.
- MX and other apex records still apply. Flattening only synthesizes A/AAAA; your apex SOA, NS, MX, and TXT records are untouched and must coexist correctly.
- Provider lock-in via ALIAS. Route 53 ALIAS and Azure alias record sets only target same-cloud resources for health-aware behavior; cross-cloud apex routing usually needs a true flattening provider.
- Empty-answer caching. Enabling flattening before the target exists can poison resolver caches with a negative answer for the full negative-TTL window; always publish the target first.
Frequently Asked Questions
Does CNAME flattening violate RFC 1034? No, when implemented correctly. The RFC prohibits a CNAME existing at the apex both in the zone file and on the wire. Flattening keeps the indirection server-side and returns ordinary RFC-compliant A/AAAA records to clients, so nothing forbidden ever appears on the wire.
Can I use CNAME flattening with DNSSEC? Yes, provided your DNS provider dynamically signs the synthesized A/AAAA records at query time. A statically pre-signed (offline) zone will fail validation because flattening changes the record set after signing, producing an RRSIG that no longer matches.
How does flattening affect CDN load balancing? It removes the extra client-side lookup, so the client connects one round trip sooner. If the CDN uses EDNS Client Subnet for geo-IP routing, the flattening server must forward ECS when it resolves the target; otherwise every client receives the same synthesized address set regardless of location.
What happens if the flattened target goes down?
The authoritative server keeps serving the last resolved addresses until their TTL expires. To minimize that exposure, keep target TTLs short, wire health-check-triggered cache purges, and choose a provider that supports automatic failover (Cloudflare proxy health, Route 53 EvaluateTargetHealth, or Azure Traffic Manager).