The zone apex has DNS constraints
A CNAME points one hostname to another but cannot be used at the zone apex (the bare domain, example.com) because the apex must also contain NS and SOA records, and a CNAME may not coexist with other records for the same name. app.example.com can be a CNAME; example.com cannot be a standards-compliant CNAME.
flowchart LR APEX["example.com<br/>zone apex"] --> AL["Alias A record<br/>to ALB"] AL --> ALB["ALB DNSName<br/>dualstack.web-alb..."] ALB --> IP["Current ALB IPs<br/>returned as A answers"] SUB["blog.example.com"] --> CN["CNAME<br/>to blog.hosting.net"] CN --> EXT["External host<br/>resolved by its own DNS"] %% step APEX: The bare domain already has NS and SOA records, so it cannot be a CNAME. %% step AL: An Alias record is an A or AAAA record whose value Route 53 looks up for you. %% step ALB: It points at an AWS resource such as an ALB, CloudFront distribution or S3 website. %% step IP: The client receives ordinary A answers with the target's current IPs, even when they change. %% step SUB: Subdomains can use a CNAME. %% step CN: A CNAME returns another name, which the resolver must look up again. %% step EXT: CNAME works for any host on the Internet, AWS or not.
Alias records
Route 53 Alias is an extension to A and AAAA records. Alias works at the apex, has no Route 53 query charge for AWS resource targets, follows IP changes of the target automatically, and can evaluate target health so that routing policies skip an unhealthy target. It points only to supported AWS resources or appropriate Route 53 records, not an arbitrary Internet hostname.
Supported targets include: ELB load balancers, CloudFront distributions, API Gateway, Elastic Beanstalk environments, S3 website endpoints, Global Accelerator, VPC interface endpoints, and other records in the same hosted zone. EC2 instance DNS names and RDS endpoints are not Alias targets — use a CNAME for an RDS endpoint.
Comparison
| CNAME | Alias | |
|---|---|---|
| Works at the apex | No | Yes |
| Target | Any hostname | Supported AWS resources, records in the zone |
| Query charge | Yes | Free for AWS resource targets |
| TTL | You set it | Uses the target's |
| Health evaluation | Only with a separate health check | Evaluate Target Health |
| Seen by clients as | CNAME, then a second lookup | Plain A/AAAA |
Creating an Alias
An ALB Alias needs the ALB DNSName and its canonical hosted zone ID. The ALB canonical hosted zone ID differs from the hosted zone containing your domain — a classic mistake.
{"Changes": [{"Action": "UPSERT", "ResourceRecordSet": {
"Name": "example.com", "Type": "A",
"AliasTarget": {"HostedZoneId": "Z1LMS91P8CMLE5",
"DNSName": "dualstack.web-alb-123.ap-southeast-1.elb.amazonaws.com",
"EvaluateTargetHealth": true}}}]}
Create a matching AAAA Alias if the load balancer is dual-stack.
| Command | Purpose |
|---|---|
aws route53 change-resource-record-sets --hosted-zone-id Z0123456789ABC --change-batch file://alias.json |
UPSERT an Alias |
aws elbv2 describe-load-balancers --names web-alb --query "LoadBalancers[0].[DNSName,CanonicalHostedZoneId]" |
Get DNSName and CanonicalHostedZoneId |
dig example.com A +short |
Confirm the apex returns IPs |
Traps: a CNAME at the apex; putting your own zone ID in AliasTarget.HostedZoneId; trying to Alias to an EC2 public DNS name.