Skip to content
SightLab Cost
Menu
EN

Blog

Cross-region data transfer: the silent budget killer

By SightLab editors networking egress finops multi-region cost

How same-cloud inter-region, cross-cloud and private-link traffic differ in cost magnitude, with real architecture mistakes and a simple region-affinity check.

Cross-region data transfer rarely appears on the architecture diagram as a first-class cost. It shows up later, as a quietly growing line on the invoice that nobody budgeted for. I have seen teams move a database replica “just for DR” and discover three months later that the replication traffic alone exceeded the cost of the primary instance.

The price difference between traffic that stays inside one region, traffic that crosses regions inside the same cloud, and traffic that leaves to another cloud or the public internet is large enough to change design decisions. Treating them as roughly the same is the most common silent budget error I still encounter.

One environment I inherited had a “global” micro-services map that looked elegant on the whiteboard. In practice almost every service talked to a shared configuration store and a central event bus that lived in a single region. The resulting inter-region tax was larger than the compute bill for those services. We did not need to abandon multi-region; we needed to make the cross-region chatter intentional and sparse.

The three magnitude bands that actually matter

Inside a single availability zone or the same region (depending on the provider) many transfers are free or extremely cheap. Cross-AZ traffic inside one region is often charged on major clouds; the rate is usually lower than inter-region but still visible at scale.

Inter-region traffic inside the same cloud (us-east-1 ↔ us-west-2, europe-west1 ↔ europe-west3, etc.) sits in a middle band. It is typically several times more expensive per GB than intra-region traffic and is billed in both directions on some providers.

Cross-cloud or public-internet egress sits in the highest band. Moving data from one hyperscaler to another, or from a cloud to an on-prem data centre over the public internet, is usually the most expensive path. Private connectivity options (Direct Connect, ExpressRoute, Interconnect, Cloud Interconnect, etc.) change the pricing model: you pay for the port/hour plus a lower per-GB rate, and the break-even depends on sustained volume.

I keep a mental model of “cheap / medium / expensive” rather than memorising every published rate. The exact numbers change; the relative order rarely does.

Typical architecture mistakes that generate the medium and expensive bands

  1. Application tier in region A, managed database in region B “for latency to another user base”. Every query and every replication stream becomes inter-region traffic.
  2. Central logging or metrics collector in one region that receives data from every other region. Log volume is easy to underestimate.
  3. Snapshot or backup copy to a second region enabled by default without a retention or frequency review.
  4. CI/CD pipelines that pull large artifacts from a registry in a distant region on every build.
  5. “Active-active” setups that continuously synchronise state across regions when eventual consistency or a single primary would have been enough.

One concrete case: a team placed the primary PostgreSQL in eu-central-1 and read replicas in us-east-1 and ap-southeast-1 for local read latency. The replication traffic, plus the application writes that still had to reach the primary, produced a steady five-figure monthly transfer bill. Moving the write path closer and making the distant replicas asynchronous and less chatty cut the transfer cost by more than half while keeping the read-latency benefit for the queries that actually needed it.

Dark professional architecture diagram showing costly cross-region DB replication vs a regionalised design with edge caching

Reducing transfer with region affinity

The cheapest byte is the one that never leaves the region. Practical techniques I use:

  • Pin compute and its primary data store to the same region unless there is a measured latency or availability reason to split them.
  • Prefer regional services (regional load balancers, regional managed databases, regional object storage) over global ones when the workload is not truly global.
  • For multi-region read traffic, push as much as possible to edge caches or regional replicas that only pull deltas.
  • Batch and compress anything that must cross regions (log shipping, backup export, analytics extracts).
  • Use private connectivity for sustained high-volume cross-cloud or hybrid flows once the volume justifies the port cost.

A quick check I run on new environments:

#!/bin/bash
# region-affinity-check.sh – very rough, provider-agnostic sketch

![Dark terminal showing region-affinity-check.sh output with WARN lines for region mismatches](/blog/en/cross-region-data-transfer-budget-killer-02-check.png)
# Expects a simple inventory file: resource,region,role

echo "=== Resources not co-located with their primary data dependency ==="
# Example logic – replace with your real inventory or cloud CLI queries
while IFS=, read -r name region role; do
  case $role in
    app)
      db_region=$(grep ",db," inventory.csv | cut -d, -f2 | head -1)
      if [[ "$region" != "$db_region" ]]; then
        echo "WARN: $name ($region) talks to db in $db_region"
      fi
      ;;
    log-shipper)
      collector_region=$(grep ",log-collector," inventory.csv | cut -d, -f2 | head -1)
      if [[ "$region" != "$collector_region" ]]; then
        echo "WARN: $name ($region) ships logs to $collector_region"
      fi
      ;;
  esac
done < inventory.csv

The script is deliberately dumb. Its value is forcing the conversation “do these two things really need to live in different regions?” before the traffic starts flowing. I have run variations of it against Terraform state or cloud inventory APIs; the exact implementation matters less than the habit of asking the question while the design is still cheap to change.

Measuring what is already happening

Most clouds expose data-transfer metrics by region pair or by service. In Cost Explorer / equivalent I filter for usage types containing “DataTransfer”, “InterRegion”, “InterZone” or the provider’s specific names, then group by source and destination region. VPC Flow Logs or equivalent packet logs can confirm the actual talkers when the billing numbers look wrong.

A practical query pattern (AWS Cost Explorer style, adapt to your provider):

# Pseudo – use the actual Cost Explorer API or CLI equivalent
# Filter: Usage type contains "DataTransfer-Out" or "InterRegion"
# Group by: Region / Availability Zone / Resource
# Look for pairs where source != destination region

I also keep a simple monthly note:

  • Top three inter-region flows by GB
  • Whether each is still justified by latency or DR requirements
  • Estimated monthly cost of those flows

After two or three months the pattern becomes obvious and new designs start avoiding the expensive pairs by default. The first month is the most important; that is when the accidental cross-region chatters are still easy to remove.

Private connectivity versus public internet

For sustained multi-hundred-GB or TB flows between clouds or to on-prem, private links often win on both cost and predictability. The calculation is roughly:

  • Public internet egress: high per-GB rate, no port fee
  • Private link: lower per-GB rate + fixed port/hour charge

There is a break-even volume. Below it the public path is cheaper; above it the private path wins and also gives more stable bandwidth. I run that comparison with the measured or forecasted monthly volume before ordering a circuit. The Egress calculator on this site is useful for the public-internet side of the comparison; the private-link quote from the provider fills in the other side.

Decision rules that have kept bills predictable

  • Default to single-region for any new service unless multi-region is a hard requirement.
  • If multi-region is required, make the cross-region traffic asynchronous, batched, or cached whenever possible.
  • Treat continuous synchronous replication across regions as an expensive feature that needs an explicit cost-benefit review.
  • Review the top inter-region flows every month for the first two quarters of a new environment; after that the surprises are rarer.
  • Prefer regional endpoints and regional service variants when the SDK or console offers both global and regional options.

These rules are deliberately conservative. It is far easier to add a second region later, with measured traffic and a clear justification, than to remove accidental cross-region chatter after it has become part of the application’s assumed topology.

Cross-region transfer is not free, and it is not a rounding error once volume grows. Making the region placement decision visible early, and measuring the resulting traffic, turns it from a silent budget killer into a controllable design parameter.

When the numbers are still higher than expected I plug the observed inter-region GB back into the Egress calculator and ask whether a different topology (more regionalisation, more caching, private link, or simply less chatty replication) would be cheaper. The answer is usually yes, and the change is usually smaller than the original architecture suggested.

I also keep a short “transfer budget” note next to the architecture decision record for any service that deliberately crosses regions. It records the expected monthly GB, the chosen path (public, private link, or batched), and the review date. When the real traffic diverges, the note makes the conversation factual instead of accusatory.

Cross-region traffic is one of the few cost items that is almost entirely under the design team’s control. Instance prices and storage rates are set by the provider; whether two components live in the same region is set by us. Treating that choice with the same seriousness as instance sizing removes the silent killer before it appears on the bill.

A last practical habit: when someone proposes a new multi-region dependency, I ask for the expected monthly GB in each direction and the latency or availability requirement that justifies it. If the answer is “we might need it later” or “it looks cleaner on the diagram”, the default stays single-region. The few times the multi-region path was truly required, the traffic estimate forced us to design the synchronisation to be cheap (async, batched, or cached) from day one.

The silent budget killer only stays silent while nobody measures it. Once the top flows are visible and attributed, the design conversation becomes straightforward and the bill follows.

Related tools

Related reading

View all posts →