Moving off Route 53: export your zone and switch nameservers

Intermediate 6 min read Updated

Route 53 can import a zone file but has no button to export one, so you list the records with the AWS CLI and convert the JSON to BIND format. Ordinary records convert one to one. Alias records (to load balancers, CloudFront, S3 or other records) have no standard equivalent: use an ALIAS record at the zone apex and a CNAME everywhere else. Weighted, latency, geolocation and failover records need a decision before you move, because they are Route 53 routing features rather than plain DNS. Then import, compare answers, lower the NS TTL, and change the nameservers at your registrar.

Contents
What you'll learn
  • How to export a Route 53 hosted zone to a BIND zone file with the AWS CLI and jq
  • How to translate alias records for ELB, CloudFront and S3
  • What to do with routing policies and health checks
  • The cutover order, including the long default NS TTL and DNSSEC

Teams leave Route 53 for the same reasons they leave any cloud-bundled DNS: they want DNS that is not tied to one cloud account, access rules a non-AWS team can use, EU hosting, or simply a panel people outside the platform team can work with. The records are easy to move. The work is in the parts that are AWS features dressed as DNS records.

1 Step 1: export the hosted zone

Find the hosted zone ID, then list every record set. The AWS CLI handles pagination for you:

aws route53 list-hosted-zones-by-name --dns-name example.com \
  --query 'HostedZones[0].Id' --output text          # /hostedzone/Z0123456789ABC

aws route53 list-resource-record-sets --hosted-zone-id Z0123456789ABC \
  --output json > example.com.json

Convert the ordinary records (everything that has ResourceRecords) to BIND lines with jq:

jq -r '.ResourceRecordSets[]
  | select(.ResourceRecords and (.SetIdentifier | not))
  | . as $r | .ResourceRecords[]
  | "\($r.Name) \($r.TTL) IN \($r.Type) \(.Value)"' example.com.json > example.com.zone

Route 53 already stores TXT values with their quotes, so they come out in valid zone file syntax. SOA and the apex NS records will be replaced by the new provider's own; leave them in the file or delete them.

The community tool cli53 can export a zone directly (cli53 export --full example.com), if you prefer not to script it.

2 Step 2: translate alias records

Alias records point at an AWS resource or at another record, and Route 53 answers with that target's addresses. They have no TTL of their own and are not exported by the command above. List them:

jq -r '.ResourceRecordSets[] | select(.AliasTarget)
  | "\(.Name) \(.Type) -> \(.AliasTarget.DNSName)"' example.com.json
Alias points atAt the zone apexOn a subdomain
Load balancer (ALB, NLB, ELB)ALIAS to the load balancer's DNS nameCNAME to the load balancer's DNS name
CloudFront distributionALIAS to dxxxxxxxx.cloudfront.netCNAME to the same
S3 static websiteALIAS to the bucket's website endpointCNAME to the website endpoint (the bucket name must match the hostname)
Another record in the same zoneALIAS to that nameCNAME to that name
; Route 53: example.com and www.example.com were alias A records to the load balancer
example.com.      300  IN  ALIAS  my-alb-123.eu-central-1.elb.amazonaws.com.
www.example.com.  300  IN  CNAME  my-alb-123.eu-central-1.elb.amazonaws.com.

Pick a TTL yourself (300 seconds is a safe start). An ALIAS record follows the target's addresses as they change, which matters for load balancers whose IPs move.

3 Step 3: decide about routing policies and health checks

Record sets with a SetIdentifier are weighted, latency-based, geolocation, geoproximity, failover or multivalue records, often tied to Route 53 health checks. Find them:

jq -r '.ResourceRecordSets[] | select(.SetIdentifier)
  | "\(.Name) \(.Type) \(.SetIdentifier) \(.Weight // .Region // .Failover // .GeoLocation // "")"' example.com.json

These are traffic-steering features, not standard DNS. For each one, choose before the move: keep a single answer (often fine for low-traffic names), move the steering into a load balancer or CDN in front of the service, or keep that name delegated to Route 53. Moving them blindly turns several answers into one random line in the zone file.

Private hosted zones stay in AWS: they only answer inside associated VPCs. If you need internal answers outside AWS, see Split-horizon DNS without running your own BIND.

4 Step 4: import, compare and cut over

  1. Import the zone file at the new provider and compare answers from both sides:
for name in example.com www.example.com api.example.com; do
  old=$(dig +short "$name" A @ns-123.awsdns-45.com | sort)
  new=$(dig +short "$name" A @ns1.primedns.net | sort)
  [ "$old" = "$new" ] || echo "DIFF $name: route53=[$old] new=[$new]"
done
  1. Lower the NS TTL in the Route 53 zone. Its NS record defaults to 172,800 seconds (two days); set it to 300 or so a couple of days before the move, together with the TTLs of records you care about.
  2. DNSSEC: if Route 53 signs the zone, remove the DS record at the registrar, wait for its TTL, and only then disable signing. See How to change DNS provider with DNSSEC enabled.
  3. Change the nameservers at your registrar. If the domain is registered with Route 53 Domains, change them under Registered domains in the Route 53 console, or transfer the domain to PrimeDNS under Domains with its auth code so registration and DNS are in one place.
  4. Keep the hosted zone for a few days after the switch, then delete it. A hosted zone is billed monthly until it is deleted.
dig +short NS example.com @a.gtld-servers.net   # the parent now delegates to the new nameservers

5 How PrimeDNS handles this

  • BIND import with a dry run, in the panel or through the API, so a script can migrate many hosted zones in one go. SOA and the apex NS records are managed by PrimeDNS.
  • ALIAS records at the apex for load balancers, CloudFront and S3 website endpoints.
  • DNS that is not tied to one cloud. The same zone serves AWS, other clouds and your offices, and split-horizon views give internal answers without a VPC.
  • Access people outside AWS can use: team roles down to a single zone instead of IAM policies, and an Audit Log with the old and new value of every change, in the panel and as CSV, without setting up a trail first.
  • EU-based service and data, and export back to BIND at any time.

If you rely on weighted, latency or failover routing for some names, keep those on a load balancer, a CDN or Route 53 for now and move the rest. Step-by-step instructions are in the zone migration guide.

6 Frequently asked questions

Can I export a Route 53 hosted zone as a BIND file?

Not from the console. List the records with aws route53 list-resource-record-sets and convert the JSON, for example with jq or the cli53 tool.

What replaces a Route 53 alias record?

An ALIAS record at the zone apex and a CNAME on subdomains, both pointing at the AWS resource's DNS name.

Why do resolvers still use Route 53 after I changed the nameservers?

They cached the old NS records, which default to two days in Route 53 and are also cached from the parent zone. Lower the NS TTL in advance and keep the hosted zone running until caches have expired.

Do I lose health checks and failover?

Yes, for records you move. Health checks and routing policies are Route 53 features; replace them with a load balancer or CDN, or keep those names on Route 53.

7 References

  1. AWS CLI: list-resource-record-sets
  2. AWS: Choosing between alias and non-alias records
  3. AWS: Choosing a routing policy
  4. cli53

Information about other providers is based on their public documentation as of October 2026. Product names and trademarks belong to their owners. Spotted something out of date? Write to This email address is being protected from spambots. You need JavaScript enabled to view it..

Take your zones out of one cloud

Convert the export, import it with a dry run, and switch when the answers match.

Create an account Read the migration guide