Migrating a zone from Route 53
DNSCove imports a Route 53 hosted zone in a single call and gives you a zero-downtime cutover: your zone starts serving on DNSCove's nameservers before you change delegation, so there's never a window where the domain resolves to nothing.
The whole migration is four steps:
- Export the hosted zone from Route 53.
- Import it into DNSCove (one API call — your AWS keys never leave your shell).
- Verify ownership with a TXT record so the zone goes live.
- Cut over your nameservers, confirm parity, and delete the old zone.
You can also do this from the console with the one-button Route 53 import; this guide shows the API path so it scripts cleanly.
Before you start
- A DNSCove tenant-admin or session token (see the quickstart for minting one).
- The AWS CLI, authenticated to read the source hosted zone.
- The hosted zone id you're migrating (
aws route53 list-hosted-zones).
export DNSCOVE=https://api.dnscove.com
export TOKEN=dnsc_… # tenant-admin token
export HOSTED_ZONE_ID=Z0123456789ABCDEFGHIJ
auth="Authorization: Bearer $TOKEN"
1. Export the hosted zone
DNSCove imports the exact JSON that list-resource-record-sets produces — no
transformation needed:
aws route53 list-resource-record-sets \
--hosted-zone-id "$HOSTED_ZONE_ID" \
--output json > zone.json
2. Import it into DNSCove
The import endpoint takes the raw Route 53 JSON wrapped in a json field. Your
AWS credentials are not sent to DNSCove — you export locally and post the
result.
curl -fsS -X POST "$DNSCOVE/api/import/route53" -H "$auth" \
-d "$(jq -Rs '{json: .}' zone.json)"
{
"zone": { "id": "Z1a2b3c4d5e6f70", "origin": "example.com.", "status": "PENDING_VERIFICATION" },
"imported": 24,
"skipped": [
{ "name": "old.example.com.", "type": "ALIAS", "reason": "alias target legacy-elb… does not resolve: no such host" }
],
"ns": ["ns1.dnscove.com.", "ns2.dnscove.org."],
"verification": {
"record": "_dnscove-challenge.example.com.",
"type": "TXT",
"value": "dnscove-site-verification=Z1a2b3c4d5e6f70"
}
}
What happened:
- Every convertible record set was recreated. Route 53 ALIAS records become DNSCove ALIAS records (apex-safe, flattened to A/AAAA at publish time and kept fresh).
skippedlists what didn't import and why. The common case is an ALIAS whose target no longer resolves — DNSCove refuses it up front rather than let a dead target break future publishes. Fix the target in DNSCove and re-add it, or drop it.- The zone is
PENDING_VERIFICATIONand not served yet. Nothing about your live domain has changed. verificationis the exact TXT record you'll publish in the next step.
Route 53's own
NSandSOAat the apex are not imported — DNSCove manages those for you and assigns ns1.dnscove.com / ns2.dnscove.org.
3. Verify ownership — the zone goes live here
Publish the verification TXT on your current DNS (still Route 53 at this point), so DNSCove can confirm you control the domain:
export ZONE=Z1a2b3c4d5e6f70
cat > verify-rr.json <<'JSON'
{ "Changes": [{ "Action": "UPSERT", "ResourceRecordSet": {
"Name": "_dnscove-challenge.example.com.", "Type": "TXT", "TTL": 60,
"ResourceRecords": [{ "Value": "\"dnscove-site-verification=Z1a2b3c4d5e6f70\"" }]
}}]}
JSON
aws route53 change-resource-record-sets \
--hosted-zone-id "$HOSTED_ZONE_ID" --change-batch file://verify-rr.json
Once that TXT is visible in public DNS, verify:
curl -fsS -X POST "$DNSCOVE/api/zones/$ZONE/verify" -H "$auth"
{ "status": "ACTIVE", "verified": true, "served": true }
The zone is now ACTIVE and answered by ns1.dnscove.com / ns2.dnscove.org —
while your nameservers still point at Route 53. Both providers now serve the
same records. (If verified comes back false, the response repeats the exact
verification record to publish and the TXT lookup it saw — give DNS a minute to
propagate and retry.)
4. Cut over and confirm
Because DNSCove already serves identical answers, switching nameservers is seamless.
a. Check parity — confirm DNSCove matches what's live before you touch delegation:
curl -fsS "$DNSCOVE/api/zones/$ZONE/parity" -H "$auth"
{ "parity": { "matches": true, "checked": 24, "mismatched": 0 }, "safe_to_delete": true }
b. Flip the nameservers at your registrar (not in Route 53) to:
ns1.dnscove.com
ns2.dnscove.org
c. Wait out the old NS TTL, re-run the parity check, and once resolvers have
moved over, delete the Route 53 hosted zone. Remove the _dnscove-challenge TXT
whenever you like — DNSCove doesn't re-check it after activation.
Notes
- Re-importing. A zone with the same origin can't be imported twice — delete the DNSCove zone first if you need a clean re-import.
- Large zones. The import is one request; very large zones (thousands of records) are best split, or imported from the console where progress is shown.
- What isn't migrated. Plain records, ALIAS, and the standard types
(
A,AAAA,CNAME,TXT,MX,NS,SRV,CAA,PTR) import cleanly. Record sets with a routing policy (weighted / latency / failover / geo — anything with a Route 53SetIdentifier) are skipped and listed inskipped, since DNSCove answers are simple. Route 53 health checks attached to a record are simply not carried over. - Least privilege after cutover. Once migrated, day-to-day record changes
only need a zone-admin token; keep the
tenant-admintoken for zone lifecycle. See the API reference.