Here’s your content formatted as a Dev.to technical blog post — structured, practical, and clean for engineers.
Deleting a hosted zone in AWS Route 53 sounds simple…
Until you see this error:
The hosted zone contains non-required resource record sets
AWS won’t let you delete a hosted zone unless all non-default records (everything except NS & SOA) are removed first.
In this guide, I’ll show you how to safely delete a hosted zone in a cascade manner using AWS CLI.
📌 Why Cascade Deletion Is Required
When you create a hosted zone in Amazon Route 53, AWS automatically creates:
-
NSrecord -
SOArecord
These two are mandatory and cannot be manually deleted.
Before deleting the hosted zone, you must:
- Delete all custom records (A, AAAA, CNAME, MX, TXT, ALIAS, etc.)
- Keep only NS and SOA
- Then delete the hosted zone
Let’s automate that.
🛠️ Prerequisites
Make sure you have:
- AWS CLI v2 installed
-
jqinstalled -
IAM permissions:
route53:ListResourceRecordSetsroute53:ChangeResourceRecordSetsroute53:DeleteHostedZoneroute53:GetHostedZone
🚀 The Cascade Delete Script
Create a file:
delete-hosted-zone-cascade.sh
Paste the following:
#!/bin/bash
# ==========================================
# Script: delete-hosted-zone-cascade.sh
# Description:
# Deletes all record sets in a Route53
# hosted zone and then deletes the zone.
# ==========================================
set -euo pipefail
HOSTED_ZONE_ID="$1"
AWS_PROFILE="${2:-default}"
if [[ -z "$HOSTED_ZONE_ID" ]]; then
echo "Usage: $0 <HOSTED_ZONE_ID> [aws_profile]"
exit 1
fi
echo "Using AWS Profile: $AWS_PROFILE"
echo "Target Hosted Zone: $HOSTED_ZONE_ID"
# Step 1: Get hosted zone name
ZONE_NAME=$(aws route53 get-hosted-zone \
--id "$HOSTED_ZONE_ID" \
--profile "$AWS_PROFILE" \
--query 'HostedZone.Name' \
--output text)
echo "Hosted Zone Name: $ZONE_NAME"
# Step 2: Fetch all record sets except default NS & SOA
echo "Fetching record sets..."
aws route53 list-resource-record-sets \
--hosted-zone-id "$HOSTED_ZONE_ID" \
--profile "$AWS_PROFILE" \
--output json \
| jq '
.ResourceRecordSets
| map(select(.Type != "NS" and .Type != "SOA"))
| map({
Action: "DELETE",
ResourceRecordSet: .
})
| {Changes: .}
' > changes.json
COUNT=$(jq '.Changes | length' changes.json)
if [[ "$COUNT" -eq 0 ]]; then
echo "No non-default records found."
else
echo "Deleting $COUNT record sets..."
aws route53 change-resource-record-sets \
--hosted-zone-id "$HOSTED_ZONE_ID" \
--change-batch file://changes.json \
--profile "$AWS_PROFILE"
sleep 10
fi
# Step 3: Delete hosted zone
echo "Deleting hosted zone..."
aws route53 delete-hosted-zone \
--id "$HOSTED_ZONE_ID" \
--profile "$AWS_PROFILE"
echo "Hosted zone $HOSTED_ZONE_ID deleted successfully."
rm -f changes.json
▶️ How to Use It
Make it executable:
chmod +x delete-hosted-zone-cascade.sh
Run it:
./delete-hosted-zone-cascade.sh Z123456ABCDEFG traced
Where:
-
Z123456ABCDEFG→ Your Hosted Zone ID -
traced→ Optional AWS CLI profile
🔍 What the Script Does (Step-by-Step)
1️⃣ Gets Hosted Zone Info
aws route53 get-hosted-zone
2️⃣ Lists All Record Sets
aws route53 list-resource-record-sets
3️⃣ Filters Out NS & SOA Using jq
Only deletes records that:
- Are NOT
NS - Are NOT
SOA
4️⃣ Submits Batch Delete
aws route53 change-resource-record-sets
5️⃣ Deletes the Hosted Zone
aws route53 delete-hosted-zone
Done. Clean and automated.
⚠️ Important Notes
- ❗ This permanently deletes all DNS records
- ❗ Cannot be undone
- ❗ If DNSSEC is enabled, disable it first
- ❗ For private hosted zones, VPC associations must be handled properly
🧠 When Is This Useful?
- CI/CD cleanup
- Destroying ephemeral environments
- Terraform drift cleanup
- Multi-account migrations
- Org account decommissioning
🛡️ Production Hardening Ideas
You may want to improve it by:
- Adding a confirmation prompt
- Waiting for change status using:
aws route53 get-change
- Logging deletion actions
- Adding a
--dry-runmode - Handling pagination for zones with many records
🎯 Final Thoughts
Manually deleting DNS records in Amazon Route 53 is painful.
Automating cascade deletion:
- Saves time
- Prevents mistakes
- Makes account cleanup predictable
- Works great in automation pipelines
If you're working heavily with AWS infrastructure, this small script will save you a lot of frustration.
Top comments (0)