The question lands in my queue almost every week, always wearing different clothes: "the team in account A needs to reach a service in account B — can you connect us?" Simple request. Except AWS gives you three completely different tools that all answer it, and picking the wrong one either costs you money forever or walls you in six months later.
I run networking for a 22-account AWS Organization, and over the years we've used all three — Transit Gateway as our backbone, peering where it quietly saves us real money, and PrivateLink in the places where the other two would have been a mistake. This is the decision framework I wish someone had handed me at account number five, with the actual costs and the practical limits that the comparison tables usually skip.
The three tools, without the marketing
VPC Peering is a cable. A private, point-to-point connection between exactly two VPCs. Traffic flows both ways, you update route tables on both sides, done. The two things that define it: it's non-transitive (A↔B and B↔C does not give A↔C, ever), and it has no hourly charge — you pay only for data transfer, and traffic that stays within the same AZ over a peering costs nothing.
Transit Gateway is a router. A managed hub that every VPC (and your VPN and Direct Connect) attaches to once. It's transitive by design — everyone attached can reach everyone else, unless you say otherwise, and "saying otherwise" is the feature: TGW route tables let you build isolated routing domains (production can't see staging, everything inbound goes through an inspection VPC) the same way a real network engineer would with VRFs. You pay for that convenience twice: per attachment-hour and per GB processed.
PrivateLink is not a network connection at all. This is the one people misfile. PrivateLink exposes one service — something behind a Network Load Balancer — as an ENI that materializes inside the consumer's VPC. There's no routing between the networks. No CIDRs exchanged. The consumer sees an IP in their own subnet and nothing else of yours. It's a socket, not a cable, and one-directional by design.
If you remember only one line from this article: PrivateLink for services, peering for pairs, Transit Gateway for networks.
The money, because it decides more than we admit
Ballpark numbers for us-east-1 at the time of writing — check the pricing pages, these move:
| Hourly | Per GB | The catch | |
|---|---|---|---|
| VPC Peering | none | data transfer only (free same-AZ, ~$0.01/GB each side cross-AZ intra-region) | cheapest by far for heavy flows |
| Transit Gateway | ~$0.05 per attachment | ~$0.02 processing on every GB | the $0.02 applies to ALL traffic, forever |
| PrivateLink | ~$0.01 per endpoint per AZ | ~$0.01 | per-service, per-consumer endpoints add up |
The number that matters is Transit Gateway's $0.02 per GB processed. It sounds like nothing until you do the multiplication that FinOps taught me to always do: a steady 1 TB/day between two accounts is roughly $600/month in TGW processing — for traffic that would ride a peering connection for a fraction of that, or for free if you keep it same-AZ. We found exactly this pattern in our environment: two accounts exchanging heavy replication traffic 24/7, dutifully routed through the TGW because "everything goes through the TGW". Moving that one pair to a direct peering paid for the time it took before the month closed.
That's not an argument against TGW. It's an argument against defaults. The TGW fee buys you transitivity, segmentation, and one attachment instead of N peerings — genuinely worth it for the general case. Just don't make your top-talker pairs pay the router tax when they don't need routing.
The framework: four questions in order
Question 1: are you connecting networks, or exposing a service? If account B just needs to consume an API that account A runs, stop — that's PrivateLink. Don't connect two entire CIDR spaces so one app can reach one port. This question alone reroutes half the requests I get, and it's also the security answer: the consumer gets an ENI, not a network path. Least privilege, but for topology.
Question 2: do the CIDRs overlap? Peering flatly refuses overlapping CIDRs, and TGW routing can't fix ambiguity either. If you're connecting to an acquired company, a partner, or your own legacy sins, overlapping ranges force the answer: PrivateLink doesn't care about CIDRs at all. It's the escape hatch that turns "we'd have to re-IP the whole environment" into a Tuesday task.
Question 3: how many VPCs, and is it growing? Two or three VPCs in a stable relationship: peer them and enjoy the free lunch. But peering meshes grow as n(n−1)/2 — at 10 VPCs that's 45 peerings and 45 pairs of route table entries to maintain, and there's a hard cap of 125 peerings per VPC before AWS stops you anyway. Somewhere between 4 and 10 VPCs, the honest math flips to TGW: one attachment each, routing managed in one place, and your on-prem connectivity (VPN/Direct Connect) plugs into the same hub. Ours flipped long ago; with 22 accounts there was no real decision left to make about the backbone.
Question 4: do you need segmentation or inspection? If compliance says production and non-production must not talk, or that cross-environment traffic goes through a firewall, TGW route tables are the tool — attach the inspection VPC, propagate routes asymmetrically, done. Peering has no equivalent; you'd be building segmentation out of security groups and hope. In our court environment, this requirement alone justified the TGW before any convenience argument.
The limits the comparison tables skip
A few practical ceilings that have bitten people I know (occasionally including me):
Peering, besides being non-transitive and capped at 125 per VPC, also doesn't propagate DNS by default — enable DNS resolution support on the connection or private hosted zone names won't resolve across it, which presents as the world's most confusing intermittent bug. Transit Gateway attachments have bandwidth ceilings (generous, up to 100 Gbps per VPC attachment these days, but VPN attachments cap at 1.25 Gbps per tunnel — plan ECMP if you need more). PrivateLink requires the service side to sit behind an NLB (or use a Gateway Load Balancer for appliances), each endpoint serves one service, and if you expose many services to many consumers, the endpoint-hours quietly become their own line item — bundle related APIs behind one NLB where it makes sense.
And one that spans all three: DNS is a separate decision. Connecting the networks doesn't make names resolve — private hosted zone associations, Resolver rules and endpoint policies are their own layer, and forgetting them is the #1 "it's connected but nothing works" cause. I wrote a whole piece on hybrid DNS for exactly this reason.
What 22 accounts actually looks like
Our topology, as a reference point rather than a prescription: a Transit Gateway backbone in the network account with separate route domains for production, non-production and shared services, an inspection VPC on the cross-domain paths, and Direct Connect into the same hub for the on-prem datacenter. Peering exists in exactly the places where a pair of VPCs exchanges heavy, predictable traffic and the TGW tax made no sense. PrivateLink exposes our shared internal services to workload accounts, and it's the only pattern we allow for anything crossing an organizational trust boundary — partners see an ENI, never a route.
Boring, explicit, and every flow has a reason it takes the path it takes. In multi-account networking, boring is the compliment.
The framework fits in one breath: expose a service → PrivateLink. Connect a stable pair (especially a chatty one) → peering. Connect many networks with segmentation and hybrid → Transit Gateway. Ask the four questions in order, run the per-GB math on your top talkers before defaulting everything to the hub, and remember DNS is always a second decision. That's it — that's the whole trick, and it took 22 accounts to learn.
I write about AWS networking from the packet up — VPC, hybrid DNS, EKS networking, and multi-account architecture. Previous articles: VPC Flow Logs with Athena and hybrid DNS with Route 53 Resolver. Follow along here or on LinkedIn.
Top comments (0)