Route 53 is the line item nobody expects to grow. It's DNS — a lookup table mapping names to addresses — and the going assumption is that a lookup table doesn't cost real money. Then a Cost Explorer pass turns up a Route 53 charge that's bigger than it should be for a service that just answers queries, and the obvious question — which query is expensive? — turns out to be the wrong one. Route 53 bills three separate things, and the one actually driving the number is rarely the one anyone assumes.
Why does Route 53 charge me anything at all?
Three independent meters, and each behaves differently:
- Hosted zones — a flat fee per zone, per month, charged whether or not the zone answers a single query.
- DNS queries — a per-million rate, tiered by the routing policy the record uses.
- Health checks — a flat fee per check, per month, plus optional features, running whether or not anything is watching the result.
The one people never expect is the first one. A hosted zone is a container for records, and AWS bills you for having the container open at all — the meter runs on existence, not traffic. That's the opposite of how most of Route 53's own marketing frames the service ("pay only for what you use"), and it's why a domain that stopped mattering two years ago is still a line item today.
Alias records are the one genuine exception. A record that's an alias to a supported AWS resource — an Application Load Balancer, a CloudFront distribution, an S3 website endpoint, an API Gateway stage — resolves for free, with no per-query charge at all. If your zone fronts mostly AWS infrastructure through alias records, the query meter barely moves and the hosted zone fee is doing almost all the work in your bill.
What do hosted zones and DNS queries actually cost?
At standard rates:
| What you pay for | Rate |
|---|---|
| Hosted zone, first 25 zones | $0.50 per zone/month |
| Hosted zone, 26th zone and beyond | $0.10 per zone/month |
| Standard queries, first 1B/month | $0.40 per million |
| Standard queries, over 1B/month | $0.20 per million |
| Latency-based routing queries, first 1B/month | $0.60 per million |
| Geolocation / geoproximity queries, first 1B | $0.70 per million |
| Alias queries to supported AWS resources | Free |
These are standard on-demand rates at the time of writing, rounded for clarity. Route 53 is a global service billed in USD (GovCloud rates differ slightly), and AWS changes prices — check the Route 53 pricing page before you build a budget on these numbers.
Run the arithmetic on a small account and the shape becomes obvious. Ten hosted zones at $0.50 each is $5/month before a single query resolves. A busy production zone answering 50 million standard queries a month adds $20. A forgotten zone for a project that shipped and shut down adds exactly the same $0.50/month it always did — it just never shows up as worth investigating, because $0.50 is below almost everyone's threshold for "worth looking into." Multiply that by however many side projects, staging environments, and acquired domains a company accumulates over a few years, and the hosted zone fee alone stops being trivial.
Why is my health checks line item so high?
Health checks are billed separately from the record they support, and that separation is where the surprise usually comes from.
| What you pay for | Rate |
|---|---|
| Health check, AWS endpoint (basic or calculated) | $0.50 per check/month |
| Health check, non-AWS endpoint (basic) | $0.75 per check/month |
| Optional feature (HTTPS, string match), AWS endpoint | +$1.00 per check/month |
| Optional feature, non-AWS endpoint | +$2.00 per check/month |
The first 50 health checks against AWS endpoints in or linked to your account are free, which is why small accounts rarely notice this meter at all. Past that allowance, or on any check pointed at a non-AWS endpoint, the fee is straightforward — until you add HTTPS validation or a string match on the response body, each of which doubles or triples a single check's cost on its own.
The real driver, though, is the same one behind hosted zones: a health check has its own lifecycle, independent of the resource it monitors. Deleting the load balancer or EC2 instance a health check was watching doesn't delete the health check. It keeps running from Route 53's global network of checkers, keeps failing (or, worse, keeps quietly passing against a replacement resource that happens to reuse the same IP), and keeps billing every month with nothing left to genuinely protect.
One more meter worth knowing about even though it's rare: Traffic Flow policy records bill $50 per record per month — two orders of magnitude above anything else on this page. Traffic Flow is powerful for complex multi-region routing, but a policy record left active after the routing scenario it was built for no longer applies is an expensive thing to forget.
How do I find out what's actually driving the number?
Start with Cost Explorer, filtered to Route 53 and grouped by Usage Type. That split separates hosted zone fees, DNS query charges, and health check charges into distinct rows in one screen, which tells you immediately which of the three meters is actually moving.
To see how many zones and records you're carrying, and how much traffic each zone answers:
# List every hosted zone and its record count
aws route53 list-hosted-zones \
--query 'HostedZones[].[Name,Id,ResourceRecordSetCount]' \
--output table
# Query volume for one hosted zone over the last 30 days — must run against us-east-1
aws cloudwatch get-metric-statistics \
--namespace AWS/Route53 \
--metric-name DNSQueries \
--dimensions Name=HostedZoneId,Value=Z1D633PJN98FT9 \
--start-time "$(date -u -d '30 days ago' +%Y-%m-%dT%H:%M:%SZ)" \
--end-time "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
--period 86400 \
--statistics Sum \
--region us-east-1 \
--output table
Route 53 publishes hosted zone metrics only in us-east-1, regardless of where your resources actually live — pointing the CLI at your usual working region returns nothing and looks like a zero-traffic zone when it isn't. A zone with a near-zero DNSQueries sum over 30 days is a genuine candidate for cleanup, not a query-logging gap.
For health checks, list what's running and cross-reference against what it's actually watching:
aws route53 list-health-checks \
--query 'HealthChecks[].[Id,HealthCheckConfig.Type,HealthCheckConfig.FullyQualifiedDomainName,HealthCheckConfig.IPAddress]' \
--output table
Anything pointing at an IP or hostname that no longer resolves to a live resource is a check paying to fail against nothing.
How do I clean this up safely?
Deleting a hosted zone removes every record in it. If the zone still holds the authoritative records for a domain someone else's DNS points at — an MX record for email, a CNAME a partner's system references, an NS delegation from a registrar — deleting it breaks that domain the moment the change propagates, and you cannot simply undelete it: recreating the zone assigns new name servers, which means updating the delegation at the registrar and waiting out DNS caching before anything works again. Confirm nothing external depends on the zone before you touch it.
For hosted zones: check ResourceRecordSetCount from the list-hosted-zones call above — a zone holding only the two default NS and SOA records was likely created and never used, which is a much safer delete than a zone with real records in it. For a zone that does have records but near-zero query volume, confirm the domain's registrar isn't still delegating to it (dig NS yourdomain.com) before deleting; a domain still delegated to a Route 53 zone with a low query count is often just quiet, not abandoned.
For health checks: delete any check whose target no longer resolves to a live resource, and downgrade optional features (HTTPS validation, string matching) on checks that don't need that level of scrutiny — a basic TCP or HTTP check is often enough to confirm an endpoint is up.
For Traffic Flow: if nobody can explain what routing scenario a $50/month policy record still implements, that's the strongest signal to retire it — confirm current traffic against the intended scenario first, since Traffic Flow is usually protecting something genuinely complex.
What else should I check while I'm in here?
Route 53 rarely sits alone. If most of your zone's records are aliases pointed at a CloudFront distribution, decommissioning that distribution doesn't clean up the DNS record pointing at it, and the hosted zone fee keeps running for a domain with nowhere left to resolve to — why CloudFront shows up on your AWS bill covers the meters on the CDN side of that same setup. If a Web ACL protects the load balancer or distribution your records point to, it has the identical outlive-the-resource problem Route 53 health checks have: what AWS WAF actually costs per month walks through that fee structure.
More broadly, a stray hosted zone or an orphaned health check is exactly the kind of small, per-resource charge that doesn't show up until you go looking for it across the account rather than one service at a time; the account-wide check worth running before the next surprise line item works through the rest of the bill in the order worth checking.
How do I catch this before it becomes a real number?
A handful of forgotten hosted zones and orphaned health checks is a five-minute cleanup once you know to look. Catching the next batch — the zone created for a project that ships next quarter and gets abandoned the quarter after, the health check nobody deletes when the resource it watched gets torn down — is the part that never happens on its own.
Connect your AWS account read-only, and Parsivex's daily anomaly checks compare every service's spend — Route 53 included — against its own trailing baseline, so a jump from a batch of new hosted zones or a Traffic Flow policy nobody remembers enabling gets flagged the next morning instead of buried in next month's bill. For how those daily checks and severity thresholds work, see cost anomaly alerts, or read how scans work for what a connected account scan reads across the rest of your bill.