This article is for anyone editing DNS (Domain Name System) records in AWS Route 53 and deciding between an alias record and a CNAME record. It usually comes up when you want example.com, with no www in front, to reach a load balancer, and Route 53 rejects the CNAME (Canonical Name) record you tried to save. The short answer is to use an alias record when the target is an AWS resource Route 53 supports, such as an application load balancer (ALB) or a CloudFront distribution (the AWS content delivery network). Reach for a CNAME when the target lives outside AWS, and keep in mind that only an alias can sit at the zone apex, your bare domain with nothing in front of it. By the end you will know which record to create for each target, and how to confirm from the command line that a name answers the way you expect.
What you are deciding
A CNAME is a real DNS record type defined by the DNS standards. It says that one name is an alias for another name, so the resolver should go and resolve that other name instead. The resolver does that second lookup, which costs an extra round trip. The standard also forbids a CNAME from coexisting with any other record at the same name. That is exactly why you cannot put one at the zone apex, where the SOA and NS records already live.
An alias record is not a DNS record type at all. It is a Route 53 feature: an internal pointer that Route 53 chases server-side at query time, then answers with the final A or AAAA records directly. The resolver never sees the indirection. That single design difference produces every practical consequence:
- Apex support. Because the answer is a plain A/AAAA record, an alias can sit at
example.comitself. This is the standard answer to the apex domain problem on AWS. - Cost. Queries to alias records pointing at AWS resources are not billed; CNAME queries are billed like any other query. On a high-traffic zone this is a real, if small, line item.
- TTL. You cannot set a TTL on an alias — Route 53 uses the TTL of the underlying resource (60 seconds for ALB targets, for example). With a CNAME you control the TTL yourself.
- Freshness. When an ALB scales and its underlying IPs change, the alias answer changes with it automatically. A CNAME to the ALB’s DNS name achieves the same end result, just one lookup later.
- Health awareness. An alias can set Evaluate target health, so Route 53 stops answering with a target whose load balancer reports no healthy instances — no separate health check needed. A CNAME knows nothing about the target’s health.
What to check first
- Is the record at the apex? Then the decision is made for you: alias (or an A record to static IPs). A CNAME will be rejected.
- Is the target an AWS resource in the supported list? ALB/NLB, CloudFront, API Gateway, S3 website endpoints, Elastic Beanstalk, Global Accelerator, VPC interface endpoints, and records in the same zone all qualify.
- Is the target a third-party service (a SaaS vendor’s verification hostname, an external CDN)? Then CNAME is the only option.
- Does anything else need to exist at that name? MX or TXT records at the same name rule out a CNAME immediately.
How to verify
Look at what a name actually returns — an alias answers with addresses, a CNAME answers with a name:
# Alias to an ALB: returns A records directly, no CNAME in the chain
dig +short app.example.com A
# CNAME: returns the target name first, then its addresses
dig app.example.com A +noall +answer
In the API, an alias is visible as an AliasTarget block instead of ResourceRecords:
aws route53 list-resource-record-sets --hosted-zone-id Z0123456789ABC \
--query "ResourceRecordSets[?Name=='app.example.com.']"
In the console, Route 53 > Hosted zones > example.com shows a toggle labeled Alias on the record edit form; when it is on, the value field becomes a picker of AWS resources in the account plus a free-form endpoint field.
The approach
- Default to alias for anything AWS. ALB, CloudFront, API Gateway custom domains, S3 static sites — alias, type A (and a second alias, type AAAA, if the target speaks IPv6, which CloudFront and dual-stack ALBs do).
- Use CNAME for external targets. Verification records for email providers, third-party status pages, external CDNs — CNAME is correct and unavoidable there.
- At the apex, alias or nothing. If your DNS is not on Route 53 and the provider offers no ANAME/flattening feature, that constraint alone is a reason to move the zone to Route 53. The registrar can stay where it is.
- Turn on Evaluate target health deliberately. For a single-region setup behind one ALB it adds little. For weighted or failover records across regions it is the mechanism that makes traffic actually shift — pair it with the load balancer health check tuning so the signal it evaluates is meaningful.
- Alias-to-alias within a zone is fine. Pointing
wwwat the apex record (or several environment names at one canonical record) keeps one place to update when the target changes.
When this is the wrong move
Alias records only exist inside Route 53, so if the zone lives at another DNS provider, the discussion is moot — you get CNAMEs and whatever apex workaround the provider offers. And an alias is not a redirect: pointing example.com at a CloudFront distribution serves the same content at that name; it does not rewrite the URL in the browser. If you want example.com to become www.example.com, that is an HTTP 301 issued by something — not a DNS trick. Finally, do not use a CNAME to an ALB at a name that also carries MX records for email; the CNAME hijacks the whole name and mail delivery breaks in confusing ways.
Common mistakes
- Creating a CNAME to
d111abcdef.cloudfront.netat the apex on a non-Route 53 provider that silently “accepts” it — some do — and breaking SOA/NS resolution for the domain. - Forgetting the AAAA alias, so IPv6-only clients (a growing share of mobile networks) fail to connect while every test from the office passes.
- Setting a long TTL on a CNAME to an AWS endpoint and then wondering why cutover during an incident takes an hour.
- Expecting Evaluate target health to work through a chain the target does not report health for — it follows alias chains, but the end target must be something with a health signal.
Keeping it under control
- Standardize: alias for AWS targets, CNAME for external, documented in the zone’s runbook.
- Audit the zone quarterly with
list-resource-record-setsand flag CNAMEs pointing at AWS resources — each one is a free upgrade to alias. - Create A and AAAA aliases together, every time, as a habit.
- Keep the zone in the same account as the workload where possible; cross-account alias targets work but the console picker will not find them, which invites typos.
The Route 53 documentation maintains the current list of supported alias targets, and it grows over time — worth a check before assuming a CNAME is required. If nobody on your team truly owns the AWS environment end to end, that is the root of most of these problems — Stack Harbor runs AWS accounts daily under AWS Operations, and you can book an AWS review.