Most of Route 53 is a handful of record types you will write over and over, plus one Route 53-only construct - the alias record - that solves a problem plain DNS cannot. This page covers both: the everyday types and when to reach for an alias instead of a CNAME.
The dividing line is simple. If you are pointing at an IP or an external hostname, use a standard record. If you are pointing at an AWS resource - especially at the zone apex - use an alias.
Standard records all share the same shape through ChangeResourceRecordSets: a Name, a Type, a TTL, and a ResourceRecords list of values. Here are the five you reach for most.
Note the details that trip people up: MX values put the priority number and the mail host in one string ("10 mail.example.com"), and TXT values must be wrapped in literal double quotes inside the string. A is IPv4, AAAA is IPv6, and both can point the same name at both address families.
A CNAME aliases one hostname to another, but it has two hard limits: it cannot exist at the zone apex, and it cannot share a name with any other record type. When you need the apex (example.com with no subdomain) to point at an AWS resource, a CNAME simply will not work. That is what the alias record is for.
An alias record has no TTL and no ResourceRecords. Instead it carries an AliasTarget with three fields: the target's canonical hosted zone id, the target's DNS name, and EvaluateTargetHealth. Here is the apex of a domain pointed at an Application Load Balancer.
# --- Python (boto3) ---r53.change_resource_record_sets( HostedZoneId="Z1234567890ABC", ChangeBatch={"Changes": [{ "Action": "UPSERT", "ResourceRecordSet": { "Name": "example.com", # the zone apex "Type": "A", # A alias -> IPv4 target "AliasTarget": { "HostedZoneId": "Z35SXDOTRQ7X7K", # the ALB's canonical zone id "DNSName": "my-alb-1234567890.us-east-1.elb.amazonaws.com", "EvaluateTargetHealth": True, }, }, }]},)
// --- TypeScript (AWS SDK v3) ---await r53.send(new ChangeResourceRecordSetsCommand({ HostedZoneId: "Z1234567890ABC", ChangeBatch: { Changes: [{ Action: "UPSERT", ResourceRecordSet: { Name: "example.com", // the zone apex Type: "A", // A alias -> IPv4 target AliasTarget: { HostedZoneId: "Z35SXDOTRQ7X7K", // the ALB's canonical zone id DNSName: "my-alb-1234567890.us-east-1.elb.amazonaws.com", EvaluateTargetHealth: true, }, }, }]},}));
The HostedZoneId inside AliasTarget is not your zone's id - it is the canonical zone id that AWS assigns to that class of target. For an ALB it is the load balancer's region-specific zone id (from DescribeLoadBalancers). CloudFront always uses Z2FDTNDATAQYW2. An S3 website endpoint has a per-region zone id. Getting this field wrong is the most common alias mistake.
Fixed per region (from the S3 website endpoints table)
API Gateway custom domain
Returned when you create the domain name
Another Route 53 record in the same zone
Your own hosted zone id
Because the ALB and S3 values are region- or resource-specific, resolve them at runtime rather than hardcoding. For CloudFront the constant is safe to inline.
Setting EvaluateTargetHealth: true ties the alias to the target's own health. For an ALB alias, Route 53 stops returning the record if the load balancer has no healthy targets. This is health checking you get for free, without creating a separate Route 53 health check - useful in failover setups covered on the health-checks page.
Aliases win at the apex and cost nothing to resolve (Route 53 does not charge for alias queries to AWS targets), and they have no TTL to tune - Route 53 manages freshness against the target. A CNAME is the right tool only when the target is not an AWS alias-eligible resource, such as an external SaaS hostname. When both would work below the apex, prefer the alias for AWS targets.
CNAME at the apex. Route 53 rejects a CNAME on the zone apex. Use an alias A/AAAA record instead.
Wrong AliasTarget HostedZoneId. Using your own zone id instead of the target's canonical id is the classic error. Pull the ALB/S3 value at runtime; CloudFront is always Z2FDTNDATAQYW2.
Putting a TTL on an alias. Alias records have no TTL field; Route 53 manages caching against the target. Including TTL with AliasTarget is invalid.
Unquoted TXT values. A TXT value must contain literal double quotes inside the string, or SPF/DKIM verification will silently fail.
CNAME sharing a name. A CNAME cannot coexist with any other record type on the same name; Route 53 rejects the change batch.
MX priority in the wrong place. The priority is part of the value string ("10 mail.example.com"), not a separate field.
A (IPv4), AAAA (IPv6), CNAME (hostname alias), TXT (verification and SPF), and MX (mail routing). Each carries a TTL and a ResourceRecords list of values.
Why can't I put a CNAME at the zone apex?
DNS forbids a CNAME coexisting with the SOA and NS records that must exist at the apex. Route 53's alias record works around this by resolving the target internally.
What is an alias record?
A Route 53-only record that points at an AWS resource through an AliasTarget (canonical hosted zone id, DNS name, and EvaluateTargetHealth) instead of a plain value and TTL.
What HostedZoneId goes inside AliasTarget?
The target's canonical hosted zone id, not your zone's. CloudFront is always Z2FDTNDATAQYW2; an ALB's is its CanonicalHostedZoneId; S3 website endpoints have a per-region id.
Do alias records have a TTL?
No. Alias records have no TTL field - Route 53 manages caching against the target's own record. Including a TTL with an AliasTarget is invalid.
When should I use a CNAME instead of an alias?
When the target is not an AWS alias-eligible resource - for example an external SaaS hostname - and the record is not at the zone apex.
What does EvaluateTargetHealth do?
When true, Route 53 considers the target's health and stops returning the alias if the target (such as an ALB with no healthy instances) is unhealthy.
How do I write a TXT record correctly?
Wrap the value in literal double quotes inside the string, for example "\"v=spf1 include:amazonses.com -all\"". Long values are split into 255-character quoted chunks.
How is an MX record formatted?
Each value is a single string with the priority and mail host together, such as "10 mail.example.com". List several values for multiple mail servers.
Are alias queries billed?
Queries to alias records that target AWS resources (ELB, CloudFront, S3, API Gateway, and Route 53 records in the same zone) are not charged, unlike standard record queries.