CNAME Flattening vs ALIAS Records at the Apex Domain

RFC 1035 strictly prohibits CNAME records at the zone apex because apex labels must coexist with the mandatory SOA and NS records — and a CNAME at the apex would make every other record type at that label undefined per RFC 1034 §3.6.2. Yet operators constantly need to point a naked domain like example.com at a CDN hostname such as d1234567890.cloudfront.net. Modern DNS providers solve this with two distinct mechanisms — CNAME flattening and ALIAS/ANAME records — that both emit synthesized A/AAAA answers on the wire while keeping a logical pointer to the target. This guide shows you how to choose between them, configure each on Cloudflare and Route 53, and verify the result with authoritative dig queries. For foundational context on authoritative vs. recursive resolution, see DNS Fundamentals & Advanced Record Configuration.

Key objectives:

  • Understand the RFC constraints that forbid an apex CNAME and how flattening and ALIAS both stay compliant
  • Distinguish server-side flattening (static target resolution) from dynamic ALIAS evaluation
  • Configure an apex alias on Cloudflare and AWS Route 53, then plan a safe rollback
  • Verify TTL inheritance and edge routing with authoritative diagnostic commands
Apex resolution: CNAME flattening vs ALIAS A recursive resolver queries the apex; both flattening and ALIAS resolve the target hostname server-side and return A and AAAA records on the wire, never a CNAME. Apex query: A/AAAA for example.com Recursive resolver Authoritative nameserver Flattening resolve target now ALIAS / ANAME eval at query time On the wire: A + AAAA only CNAME at apex → SERVFAIL

Architectural Differences: Server-Side vs. Pseudo-Records

CNAME flattening operates entirely on the authoritative nameserver. When a recursive resolver queries the apex, the provider resolves the target CNAME to its underlying A/AAAA records server-side before returning the response. The wire protocol never exposes a CNAME at the root — the client sees only A/AAAA records, so the answer is indistinguishable from a hand-maintained static A record.

ALIAS records (also branded ANAME by some vendors) are provider-specific pseudo-records stored in the zone configuration, not on the wire. They are evaluated dynamically at query time by the authoritative server. Like flattening, they return A/AAAA responses to clients, but the zone maintains a logical pointer to the target hostname so the published IPs track the target as it changes. This distinction matters most during edge migrations and failover, where the relationship between TTL strategy and propagation determines how quickly resolvers pick up new IPs.

Symptom: Recursive resolvers return SERVFAIL or NXDOMAIN for apex queries. Root cause: Legacy DNS implementations reject CNAMEs at the apex due to the RFC 1035 coexistence rule. Resolution: Deploy flattening for static target resolution or ALIAS for dynamic routing. Both maintain strict wire-protocol compliance.

TTL behavior diverges between these methods. Flattening inherits the target record’s TTL at query time — if the target CDN publishes a 300-second TTL, recursive resolvers cache that value even when your zone specifies something longer. ALIAS implementations typically enforce a configurable minimum TTL (often 60 seconds), enabling faster cache invalidation. Because both mechanisms emit dual-stack answers, the same A vs AAAA configuration concerns for IPv6 migration apply: confirm your target actually publishes AAAA records before assuming the apex will serve IPv6.

Prerequisites and Environment Setup

Before configuring an apex alias, confirm the following:

  • A target hostname, not a target IP. Flattening and ALIAS both point at a name (for example d1234567890.cloudfront.net or myapp.vercel.app), and that name’s own A/AAAA records must already resolve.
  • Authoritative access to the zone — the Cloudflare dashboard/API token with DNS edit scope, or a Route 53 hosted zone plus an IAM principal allowed to call route53:ChangeResourceRecordSets.
  • Tooling: dig (from bind-utils / dnsutils), curl, the aws CLI v2, and jq for parsing API responses.
  • A rollback target IP for the origin, in case the alias misroutes traffic and you need to fall back to a static A record.
# Confirm the target hostname itself resolves before you alias to it
dig d1234567890.cloudfront.net A +short
dig d1234567890.cloudfront.net AAAA +short

Expected output: one or more public IPs per family. An empty AAAA result is fine, but means your apex will be IPv4-only.

Step-by-Step Configuration

Step 1 — Choose the mechanism for your provider

Implementation varies by platform. For deeper background on the resolver logic, see CNAME Flattening Explained.

  • Cloudflare enables automatic CNAME flattening at the zone apex. You simply create a CNAME record on @; the platform intercepts the target and serves A/AAAA records directly. Flattening applies only to the root unless you switch the zone to flatten_all.
  • AWS Route 53 uses a native ALIAS type in the console and API. It never exposes a literal ALIAS on the wire — it returns A/AAAA records with the alias target’s current IPs. The AliasTarget.HostedZoneId must match the hosted zone of the target service (for example Z2FDTNDATAQYW2 for CloudFront).
  • NS1, DNSimple, and others support ALIAS or ANAME, sometimes with a flattening toggle; availability varies by plan tier.

Step 2 — Create the apex CNAME on Cloudflare

On Cloudflare, add a CNAME on the root label; flattening is applied automatically.

curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/dns_records" \
  -H "Authorization: Bearer $CF_API_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
    "type": "CNAME",
    "name": "@",
    "content": "d1234567890.cloudfront.net",
    "ttl": 1,
    "proxied": false
  }' | jq '.result.id, .result.name'

Expected output: a record ID and "example.com". A ttl of 1 means “automatic”. With proxied: false (DNS-only) the apex resolves to the target’s IPs; with proxied: true it resolves to Cloudflare’s anycast IPs instead.

Step 3 — Create the ALIAS record on Route 53

For Route 53, write a change batch describing the ALIAS, then apply it. Note there is no TTL field — Route 53 controls caching itself.

{
  "Comment": "Create ALIAS for apex domain",
  "Changes": [
    {
      "Action": "UPSERT",
      "ResourceRecordSet": {
        "Name": "example.com.",
        "Type": "A",
        "AliasTarget": {
          "HostedZoneId": "Z2FDTNDATAQYW2",
          "DNSName": "d1234567890.cloudfront.net.",
          "EvaluateTargetHealth": false
        }
      }
    }
  ]
}

Apply via the AWS CLI:

aws route53 change-resource-record-sets \
  --hosted-zone-id Z12345EXAMPLE \
  --change-batch file://alias-batch.json

Expected output: a ChangeInfo block with "Status": "PENDING". Repeat the batch with "Type": "AAAA" to serve IPv6 from the same alias target.

Step 4 — Confirm the active mechanism via API

Read back the provider state so you know which mechanism is live before testing the wire.

# Cloudflare: confirm flattening mode for the zone
curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$CF_ZONE_ID/settings/cname_flattening" \
  -H "Authorization: Bearer $CF_API_TOKEN" \
  -H "Content-Type: application/json" | jq '.result.value'

Expected output: "flatten_at_root" (default) or "flatten_all". On Route 53, confirm the ALIAS exists with aws route53 list-resource-record-sets --hosted-zone-id Z12345EXAMPLE --query "ResourceRecordSets[?Name=='example.com.']".

Step 5 — Plan the rollback

If routing fails post-configuration, immediately revert the apex to a static A record pointing at your origin IP. On Route 53 you must DELETE the ALIAS (with an exact-match change batch) before you can UPSERT a standard A record. On Cloudflare you delete the apex CNAME and add an A record, or toggle the proxy. Keep the origin IP and a pre-written rollback batch staged so the change is a single command under pressure.

Verification

Always query the authoritative nameserver directly to bypass recursive resolver caches, then compare against a public resolver.

# Compare authoritative vs. recursive responses
echo "=== Authoritative ===" && dig @ns1.cloudflare.com example.com A +noall +answer
echo "=== Recursive ===" && dig @8.8.8.8 example.com A +noall +answer

Expected output: both sections contain only A records — no CNAME line at the apex.

=== Authoritative ===
example.com.   300  IN  A  13.33.12.45
=== Recursive ===
example.com.   287  IN  A  13.33.12.45

If both return identical A records, flattening or ALIAS is functioning correctly. A CNAME in the answer at the apex indicates misconfiguration. Next, confirm the IPs actually terminate at your CDN edge:

# Verify CDN edge routing end to end
dig example.com A +noall +answer && curl -sI https://example.com | head -n 3

Cross-reference the returned IP pool against your CDN provider’s published edge ranges. A server: or via: header from your CDN in the curl output confirms the request reached the intended edge.

Troubleshooting

Symptom: Intermittent 5xx errors or stale routing after the target updates its IP pool. Diagnosis: Recursive resolvers cache flattened A/AAAA records for the inherited TTL, ignoring upstream changes during that window. Confirm with dig example.com A +ttlunits and compare the remaining TTL against the target’s published value. Fix: Prefer ALIAS with a low minimum TTL during migrations, or lower the target’s TTL before the cutover. Validate authoritative answers against recursive output to confirm convergence.

Symptom: Slow failover during a CDN regional outage. Diagnosis: A high inherited TTL on flattened records prevents resolvers from fetching updated A records promptly. Fix: Migrate to ALIAS with a low minimum TTL and enable target health evaluation (EvaluateTargetHealth: true on Route 53). Watch query timing across resolvers:

dig example.com A +stats | grep 'Query time'

Low, consistent query times across resolvers indicate healthy cache behavior; high variance suggests resolvers are honoring stale TTLs.

Symptom: DNSSEC validation breaks after enabling flattening. Diagnosis: If the provider does not sign the synthesized A/AAAA records, RRSIG validation fails and validating resolvers return SERVFAIL. Fix: Verify DNSSEC compatibility in provider documentation; prefer a provider whose flattening signs synthesized answers, or use ALIAS. Coordinate the change with your overall DNS zone management process so signing and key state stay consistent.

Symptom: Email or service discovery breaks after configuring the apex alias. Diagnosis: A buggy implementation suppressed MX/SRV/TXT records at the apex when flattening the A/AAAA set. Fix: Confirm coexisting records survive with dig example.com MX +short and dig example.com TXT +short immediately after the change.

Edge Cases and Warnings

Scenario Impact Mitigation
Target CDN changes IP pool without TTL update Stale A records route traffic to decommissioned edge nodes Use ALIAS with low minimum TTL; poll with dig during migrations
DNSSEC signing with flattened records RRSIG validation breaks if the provider does not sign synthesized A/AAAA Verify DNSSEC support; prefer ALIAS if signing is strictly enforced
MX/SRV conflicts during apex flattening Legacy implementations may suppress non-A record types at the apex Verify dig example.com MX +short returns mail records post-change
Mixing ALIAS and flattening on one apex Undefined precedence and unpredictable answers Pick one mechanism per apex; they are mutually exclusive

Frequently Asked Questions

Does CNAME flattening violate RFC 1035? No. Flattening occurs server-side at the authoritative nameserver, which returns A/AAAA records to the recursive resolver. The wire protocol never carries a CNAME at the apex, so RFC compliance is preserved.

Can I use both ALIAS and CNAME flattening on the same apex record? No. They are mutually exclusive resolution mechanisms. Choose ALIAS for dynamic TTL control and health checks, or flattening for inherited-TTL resolution of a static CDN target.

How do I verify whether my provider uses flattening or ALIAS? Query the authoritative nameserver directly with dig @ns1.provider.com example.com A +noall +answer. If it returns A/AAAA records rather than a CNAME, flattening or ALIAS is active. The wire output is identical between the two, so consult provider documentation for the exact mechanism.

Does ALIAS support wildcard apex routing? No. RFC constraints prohibit CNAME-like behavior at the zone root, and wildcards do not apply to the apex itself. Configure wildcards at subdomain levels (*.example.com) using standard CNAME or A/AAAA records.

Will the apex serve IPv6 automatically? Only if the target hostname publishes AAAA records and you create the matching alias. On Route 53, add a separate AAAA ALIAS; with Cloudflare flattening, AAAA is served when the target resolves over IPv6.

Back to CNAME Flattening Explained