GreenOps

© 2026 GreenOps. All rights reserved.

npx greenops-scanBlogPrivacy PolicyTermsRefund PolicyMethodology
GreenOps
ProblemSolutionPricingBlognpx greenops-scan
Sign in / Sign upFree audit
← Back to blog
GreenOps dashboard preview

The $0.02/GB Charge That Never Shows Up as Its Own Line Item

Availability Zones make your app resilient. They also meter every byte between them.

AWS splits every region into multiple Availability Zones so a single data center failure doesn't take your application down. That resilience has a price: traffic that crosses an AZ boundary — Multi-AZ RDS replication, a load balancer routing to a target in another zone, an ECS task calling a database replica scheduled elsewhere — is billed at roughly $0.01/GB in each direction, so effectively $0.02/GB round-trip, on top of whatever the service itself already costs.

It's a real, well-known AWS billing behavior. What's less well known is that it almost never shows up as its own line item. Cost Explorer's default service breakdown shows "Amazon RDS," "EC2-Other," "Amazon Elastic Load Balancing" — the cross-AZ transfer charge is folded into whichever service generated it, not broken out on its own. You can be paying it every month without a single row in your bill that says "cross-AZ data transfer."

Where it actually comes from

  • Multi-AZ RDS/Aurora — every write is synchronously replicated to the standby in another AZ. That replication stream is cross-AZ traffic, continuously, for the life of the database.
  • ALB/NLB cross-zone load balancing — if targets are spread across AZs (the normal, recommended setup) and cross-zone balancing is on, a request landing on the load balancer in AZ-a can be routed to a target in AZ-b.
  • EKS/ECS workloads split across AZs — the standard, resilient way to run a cluster — talking to a database, cache, or each other. A chatty microservice architecture with pods scheduled across 3 AZs can generate meaningfully more cross-AZ chatter than a monolith ever would.
  • VPC-peered or Transit Gateway-routed traffic that happens to cross AZs along the way.

None of this is a mistake. Multi-AZ and cross-AZ load balancing are the correct way to run resilient infrastructure — this isn't a "turn it off" finding like an idle instance. It's a cost that comes bundled with an architecture decision most teams made for the right reasons and then never measured.

Where to actually find it in AWS's own data

AWS does track this at a granular level — it's just one dimension deeper than the default view. GetCostAndUsage grouped by USAGE_TYPE (not just SERVICE) surfaces usage types with a -DataTransfer-Regional-Bytes suffix, region-code-prefixed (USE1-DataTransfer-Regional-Bytes for us-east-1, EUC1-... for eu-central-1, and so on) — AWS's own label for "this byte crossed an AZ boundary inside the region."

aws ce get-cost-and-usage \
  --time-period Start=$(date -v-1m +%Y-%m-01),End=$(date +%Y-%m-01) \
  --granularity MONTHLY \
  --metrics UnblendedCost \
  --group-by Type=DIMENSION,Key=SERVICE Type=DIMENSION,Key=USAGE_TYPE \
  --query "ResultsByTime[0].Groups[?contains(Keys[1], 'DataTransfer-Regional-Bytes')]"

(On Linux, swap date -v-1m for date -d 'last month'.)

If that query returns nothing, your account genuinely isn't generating billable cross-AZ traffic worth worrying about — which is a perfectly normal, good outcome for a smaller or single-AZ-heavy account. If it returns a number, that's real spend currently living anonymously inside your RDS/EC2/ELB bill.

What GreenOps Scan does with it

This is one of the rare findings that costs zero new IAM permissions or API calls: ce:GetCostAndUsage grouped by SERVICE + USAGE_TYPE is a call the scanner already makes for its billing summary, to extract Lambda-specific usage costs. Cross-AZ transfer just needed its own filter on the same response.

  - severity: MEDIUM
    module: VPC-ENDPOINTS
    resource: 123456789012
    resourceType: AWS Account
    issue: $18.40 spent last month on inter-AZ ("regional") data transfer — traffic crossing Availability Zone boundaries within the region, billed separately from the services generating it
    costSavings: $18.40/mo
    confidence: LOW
    co2Savings: 0.00 kg/mo
    recommendation: Review Multi-AZ replication, ALB/NLB cross-zone routing, and whether workloads (ECS/EKS tasks, Lambda, EC2) that talk to each other frequently can be pinned to the same AZ as their dependencies — this is a data-mix and architecture cost, not a single resource to delete

That's an illustrative shape. Confidence is reported as low on purpose: Cost Explorer's USAGE_TYPE grouping tells you how much crossed an AZ boundary and what it cost, but not which two resources were talking to each other — that detail lives in VPC Flow Logs, not billing data. The scanner surfaces the number so you know whether it's worth digging into; it doesn't pretend to know the exact wiring.

What's actually worth doing about it

Unlike most findings in this scanner, there's no single command that fixes this — because in most cases, nothing is wrong. The options, roughly in order of effort:

  • Check if ALB/NLB cross-zone load balancing is costing you specifically. For Network Load Balancers, cross-zone balancing is billed per GB and is off by default; if it's on and your targets are unevenly distributed, turning it off (and relying on even AZ-level target distribution instead) removes that slice cleanly. For ALBs, cross-zone is always on and not separately billed the same way — this lever mainly applies to NLBs.
  • Look at whether chatty services can be topology-aware. Kubernetes' built-in topology-aware routing (or an ECS service discovery setup that prefers same-AZ targets) keeps traffic local when a same-AZ replica is available, and only crosses zones as a fallback. This is a real engineering change, not a config flip — worth it only once the number justifies it.
  • Accept it for Multi-AZ RDS/Aurora. The replication stream to the standby is the entire point of Multi-AZ — that's not overhead to eliminate, it's what you're paying for. The only lever here is the Multi-AZ-on-non-prod finding this scanner already flags separately, which asks whether you need that resilience at all in a staging environment.
  • Measure before architecting. For most accounts, this number will be small enough that redesigning traffic patterns around it isn't worth the engineering time. That's the actual point of surfacing it: turning "we assume this doesn't matter" into "we checked, and it's $3/month" or "we checked, and it's $400/month and climbing" — two very different next steps.

Check it in one command

npx greenops-scan --modules vpc-endpoints

If the number that comes back is small, that's not a wasted scan — it's confirmation that a well-known AWS billing gotcha isn't quietly compounding in your account. If it's bigger than expected, it's the first concrete number you've had to decide whether cross-zone traffic patterns are worth re-architecting around.

Tags: #AWS #CloudCostOptimization #FinOps #DataTransfer #NetworkCosts #GreenOps

More posts

View all posts →

Your AWS Logs Never Expire — and CloudWatch Has Other Meters Running

CloudWatch bills on six meters at once, and its defaults compound forever: log groups with no retention, $0.50/GB ingestion, per-dimension custom metrics, and the GetMetricData polling tax behind third-party monitoring bills.

The $0.045/GB Mistake Hiding in Almost Every AWS VPC

A missing free Gateway VPC Endpoint silently routes S3/DynamoDB traffic through your NAT Gateway at $0.045/GB — the well-known "$1,000 AWS mistake," and why it's worth checking even in accounts that fixed it once already.

Every Finding Now Tells You Which Team, Project, and Stack Owns It

GreenOps Scan now attaches each flagged resource's AWS tags — Project, Environment, Team, even the exact CloudFormation stack and logical ID — straight into every finding, no new IAM permissions required.