AWS Transit Gateway: Multi-VPC and Hybrid Networking
As AWS architectures grow, connecting dozens of VPCs to each other and to on-premises networks becomes a serious operational challenge. VPC peering works fine for three or four VPCs, but the mesh explodes combinatorially — 10 VPCs would need 45 peering connections; 50 VPCs need 1,225. AWS Transit Gateway (TGW) solves this by acting as a regional network hub: you attach all your VPCs and on-premises connections to one TGW, and it routes traffic between them. This guide covers architecture design, full CLI setup, hybrid connectivity, inter-region peering, and cost optimization.
Table of Contents
- Transit Gateway vs VPC Peering vs PrivateLink
- TGW Architecture: Attachments, Route Tables, Associations
- Multi-VPC Hub-and-Spoke Topology: Full CLI Setup
- Hybrid Connectivity: VPN and Direct Connect Attachments
- Inter-Region TGW Peering
- Multicast Support and ECMP
- AWS Network Manager for Centralized Visibility
- Cost Breakdown and Optimization Tips
- Frequently Asked Questions
Transit Gateway vs VPC Peering vs PrivateLink
Before choosing a connectivity strategy, understand the trade-offs between the three primary options. Each solves a different problem at a different price point.
| Feature | VPC Peering | AWS PrivateLink | Transit Gateway |
|---|---|---|---|
| Traffic model | Peer-to-peer (1:1) | Service-to-consumer (1:N) | Hub-and-spoke (N:N) |
| Transitive routing | No | No | Yes |
| Connections required for 10 VPCs | 45 peering connections | N/A (service-based) | 10 attachments to 1 TGW |
| Cross-region support | Yes (inter-region peering) | No (same-region only) | Yes (TGW peering) |
| Bandwidth limit | Up to 50 Gbps per pair | 10 Gbps per ENI | Up to 50 Gbps per AZ (ECMP) |
| On-premises connectivity | No | No | Yes (VPN + Direct Connect) |
| Overlapping CIDRs | Not supported | Supported (NLB-based) | Not supported natively |
| Cost model | Data transfer only | Per-hour + data | Per-hour + data per GB |
| Best for | Simple 2-3 VPC connectivity | Sharing a service across many consumers | Large multi-VPC and hybrid networks |
TGW Architecture: Attachments, Route Tables, Associations, Propagations
Transit Gateway has four core concepts you must understand before you create anything:
- Attachment — a logical connection between TGW and a resource. Types: VPC, VPN, Direct Connect Gateway, TGW Peering, and Connect (SD-WAN appliances). Each VPC attachment picks up to one subnet per Availability Zone to place the TGW ENI in.
- Route Table — a TGW-side routing table (separate from your VPC route tables). You can have multiple TGW route tables to segment traffic — for example, one for production VPCs and one for shared-services VPCs.
- Association — links an attachment to exactly one TGW route table. Incoming traffic from that attachment is looked up in this route table.
- Propagation — automatically advertises the CIDR of an attachment into a route table. Without propagation you must add static routes manually.
The traffic flow for a packet going from VPC-A to VPC-B is: VPC-A instance → VPC-A route table (default route or specific route pointing to TGW) → TGW → TGW route table associated with VPC-A attachment (looks up VPC-B CIDR, finds propagated route pointing to VPC-B attachment) → VPC-B attachment → VPC-B.
Multi-VPC Hub-and-Spoke Topology: Full CLI Setup
The following walkthrough creates a TGW, attaches three VPCs (a shared-services VPC and two workload VPCs), configures route tables, and enables propagations. Replace the placeholder IDs with your real resource IDs.
Step 1: Create the Transit Gateway
# Create TGW with ASN 64512 (private BGP ASN range)
aws ec2 create-transit-gateway \
--description "prod-tgw" \
--options AmazonSideAsn=64512,\
AutoAcceptSharedAttachments=disable,\
DefaultRouteTableAssociation=disable,\
DefaultRouteTablePropagation=disable,\
DnsSupport=enable,\
VpnEcmpSupport=enable,\
MulticastSupport=enable \
--tag-specifications 'ResourceType=transit-gateway,Tags=[{Key=Name,Value=prod-tgw}]'
# Note the TransitGatewayId from the output, e.g. tgw-0abc123def456789a
TGW_ID=tgw-0abc123def456789a
DefaultRouteTableAssociation=disable and DefaultRouteTablePropagation=disable gives you full control — attachments won't automatically land in a default route table. This is the recommended production pattern so you can segment traffic between environments.Step 2: Create TGW Route Tables
# Route table for shared-services VPC (DNS, monitoring, bastion)
aws ec2 create-transit-gateway-route-table \
--transit-gateway-id $TGW_ID \
--tag-specifications 'ResourceType=transit-gateway-route-table,Tags=[{Key=Name,Value=tgw-rt-shared}]'
SHARED_RT=tgw-rtb-0shared1234567890a
# Route table for workload VPCs (prod, staging, etc.)
aws ec2 create-transit-gateway-route-table \
--transit-gateway-id $TGW_ID \
--tag-specifications 'ResourceType=transit-gateway-route-table,Tags=[{Key=Name,Value=tgw-rt-workloads}]'
WORKLOAD_RT=tgw-rtb-0workload234567890b
Step 3: Attach VPCs
# Attach shared-services VPC (one subnet per AZ)
aws ec2 create-transit-gateway-vpc-attachment \
--transit-gateway-id $TGW_ID \
--vpc-id vpc-0shared000000000 \
--subnet-ids subnet-0aaa111 subnet-0aaa222 \
--tag-specifications 'ResourceType=transit-gateway-attachment,Tags=[{Key=Name,Value=attach-shared-svc}]'
SHARED_ATTACH=tgw-attach-0shared1
# Attach prod workload VPC
aws ec2 create-transit-gateway-vpc-attachment \
--transit-gateway-id $TGW_ID \
--vpc-id vpc-0prod0000000000 \
--subnet-ids subnet-0bbb111 subnet-0bbb222 \
--tag-specifications 'ResourceType=transit-gateway-attachment,Tags=[{Key=Name,Value=attach-prod}]'
PROD_ATTACH=tgw-attach-0prod1
# Attach staging workload VPC
aws ec2 create-transit-gateway-vpc-attachment \
--transit-gateway-id $TGW_ID \
--vpc-id vpc-0staging00000000 \
--subnet-ids subnet-0ccc111 subnet-0ccc222 \
--tag-specifications 'ResourceType=transit-gateway-attachment,Tags=[{Key=Name,Value=attach-staging}]'
STAGING_ATTACH=tgw-attach-0staging1
Step 4: Associate Attachments to Route Tables
# Shared-services attachment uses shared route table
aws ec2 associate-transit-gateway-route-table \
--transit-gateway-route-table-id $SHARED_RT \
--transit-gateway-attachment-id $SHARED_ATTACH
# Prod and staging use workload route table
aws ec2 associate-transit-gateway-route-table \
--transit-gateway-route-table-id $WORKLOAD_RT \
--transit-gateway-attachment-id $PROD_ATTACH
aws ec2 associate-transit-gateway-route-table \
--transit-gateway-route-table-id $WORKLOAD_RT \
--transit-gateway-attachment-id $STAGING_ATTACH
Step 5: Enable Propagations
# Workload VPCs propagate their CIDRs into the shared route table
# so shared-services (DNS, monitoring) can reach back to them
aws ec2 enable-transit-gateway-route-table-propagation \
--transit-gateway-route-table-id $SHARED_RT \
--transit-gateway-attachment-id $PROD_ATTACH
aws ec2 enable-transit-gateway-route-table-propagation \
--transit-gateway-route-table-id $SHARED_RT \
--transit-gateway-attachment-id $STAGING_ATTACH
# Shared-services VPC propagates into workload route table
# so prod/staging can reach shared services (10.0.0.0/16)
aws ec2 enable-transit-gateway-route-table-propagation \
--transit-gateway-route-table-id $WORKLOAD_RT \
--transit-gateway-attachment-id $SHARED_ATTACH
# Workloads do NOT propagate into each other's route table
# Prod and staging are isolated — they can only reach shared-services
Step 6: Update VPC Route Tables
Each VPC's subnet route table needs a route pointing cross-VPC traffic toward the TGW. You need to do this for every subnet that should participate in transit routing.
# In the prod VPC: route to shared-services CIDR via TGW
aws ec2 create-route \
--route-table-id rtb-prod-private \
--destination-cidr-block 10.0.0.0/16 \
--transit-gateway-id $TGW_ID
# In the prod VPC: default route for internet via TGW (if using centralized egress)
# aws ec2 create-route \
# --route-table-id rtb-prod-private \
# --destination-cidr-block 0.0.0.0/0 \
# --transit-gateway-id $TGW_ID
# In the shared-services VPC: route to prod CIDR via TGW
aws ec2 create-route \
--route-table-id rtb-shared-private \
--destination-cidr-block 10.10.0.0/16 \
--transit-gateway-id $TGW_ID
# In the shared-services VPC: route to staging CIDR via TGW
aws ec2 create-route \
--route-table-id rtb-shared-private \
--destination-cidr-block 10.20.0.0/16 \
--transit-gateway-id $TGW_ID
Hybrid Connectivity: VPN Attachments and Direct Connect Integration
One of TGW's biggest advantages over VPC peering is that a single on-premises connection can be shared across all attached VPCs. Instead of creating separate VPN tunnels or Direct Connect Virtual Interfaces for each VPC, you connect once to the TGW and propagate the on-premises routes into any VPC route table you choose.
Site-to-Site VPN Attachment
# Step 1: Create a Customer Gateway for your on-premises router
aws ec2 create-customer-gateway \
--type ipsec.1 \
--public-ip 203.0.113.10 \
--bgp-asn 65000 \
--tag-specifications 'ResourceType=customer-gateway,Tags=[{Key=Name,Value=onprem-cgw}]'
CGW_ID=cgw-0abc123
# Step 2: Create VPN attachment directly on the TGW
# (no Virtual Private Gateway needed — TGW is the gateway)
aws ec2 create-vpn-connection \
--type ipsec.1 \
--customer-gateway-id $CGW_ID \
--transit-gateway-id $TGW_ID \
--options TunnelOptions='[
{
"TunnelInsideCidr":"169.254.10.0/30",
"PreSharedKey":"your-psk-tunnel1"
},
{
"TunnelInsideCidr":"169.254.10.4/30",
"PreSharedKey":"your-psk-tunnel2"
}
]' \
--tag-specifications 'ResourceType=vpn-connection,Tags=[{Key=Name,Value=onprem-vpn}]'
VPN_ATTACH_ID=tgw-attach-0vpn1
# Step 3: Associate the VPN attachment with a route table
aws ec2 associate-transit-gateway-route-table \
--transit-gateway-route-table-id $WORKLOAD_RT \
--transit-gateway-attachment-id $VPN_ATTACH_ID
# Step 4: Propagate on-premises routes (BGP) into VPC route tables
aws ec2 enable-transit-gateway-route-table-propagation \
--transit-gateway-route-table-id $WORKLOAD_RT \
--transit-gateway-attachment-id $VPN_ATTACH_ID
# Step 5: Allow workload VPCs to propagate routes back to on-premises
# (so on-premises can reach your VPC CIDRs via BGP)
aws ec2 enable-transit-gateway-route-table-propagation \
--transit-gateway-route-table-id $SHARED_RT \
--transit-gateway-attachment-id $VPN_ATTACH_ID
Direct Connect Integration via DXGW
For production hybrid connectivity, Direct Connect provides dedicated private bandwidth (1 Gbps to 100 Gbps) and consistent latency. The integration path is: on-premises router → Direct Connect location → AWS Direct Connect Gateway (DXGW) → TGW attachment.
# Direct Connect Gateway bridges DX circuits to TGW
# (Created in the console or via CLI)
aws directconnect create-direct-connect-gateway \
--direct-connect-gateway-name prod-dxgw \
--amazon-side-asn 64513
DXGW_ID=090dd3c2-9534-4b00-9ae9-0bc97fb1e5c8
# Associate DXGW with your TGW
aws directconnect create-transit-virtual-interface \
--connection-id dxcon-fnoiqf5q \
--new-transit-virtual-interface '{
"virtualInterfaceName": "prod-transit-vif",
"vlan": 100,
"asn": 65000,
"mtu": 8500,
"authKey": "your-bgp-auth-key",
"amazonAddress": "169.254.255.1/30",
"customerAddress": "169.254.255.2/30",
"addressFamily": "ipv4",
"directConnectGatewayId": "'$DXGW_ID'"
}'
# Associate the DXGW with the TGW
aws directconnect create-direct-connect-gateway-association \
--direct-connect-gateway-id $DXGW_ID \
--gateway-id $TGW_ID \
--add-allowed-prefixes-to-direct-connect-gateway \
cidr=10.0.0.0/16 cidr=10.10.0.0/16 cidr=10.20.0.0/16
Inter-Region TGW Peering
When your architecture spans multiple AWS regions (for disaster recovery, data sovereignty, or latency optimization), you can peer two TGW instances together. Traffic traverses the AWS global backbone — lower latency and higher reliability than the public internet, but you pay inter-region data transfer charges.
# In us-east-1: get the TGW ID
US_EAST_TGW=tgw-0useast1234567890
# In ap-south-1: get the TGW ID
AP_SOUTH_TGW=tgw-0apsouth1234567890
# From us-east-1: create peering attachment to ap-south-1 TGW
aws ec2 create-transit-gateway-peering-attachment \
--transit-gateway-id $US_EAST_TGW \
--peer-transit-gateway-id $AP_SOUTH_TGW \
--peer-account-id 123456789012 \
--peer-region ap-south-1 \
--tag-specifications 'ResourceType=transit-gateway-attachment,Tags=[{Key=Name,Value=tgw-peer-us-ap}]' \
--region us-east-1
PEER_ATTACH_ID=tgw-attach-0peer1234567890
# From ap-south-1: accept the peering request
aws ec2 accept-transit-gateway-peering-attachment \
--transit-gateway-attachment-id $PEER_ATTACH_ID \
--region ap-south-1
# Add static routes in each region pointing to the other region's CIDRs
# In us-east-1 route table: route ap-south-1 CIDR via the peering attachment
aws ec2 create-transit-gateway-route \
--transit-gateway-route-table-id $WORKLOAD_RT \
--destination-cidr-block 172.16.0.0/16 \
--transit-gateway-attachment-id $PEER_ATTACH_ID \
--region us-east-1
# In ap-south-1 route table: route us-east-1 CIDR back
aws ec2 create-transit-gateway-route \
--transit-gateway-route-table-id tgw-rtb-0apsouth \
--destination-cidr-block 10.0.0.0/8 \
--transit-gateway-attachment-id $PEER_ATTACH_ID \
--region ap-south-1
Multicast Support and ECMP for Bandwidth
Multicast
Transit Gateway supports multicast traffic — one-to-many packet delivery without replication at the sender. This is useful for financial market data feeds, video distribution, and real-time telemetry. You must enable MulticastSupport=enable at TGW creation time (it cannot be changed later).
# Create a multicast domain
aws ec2 create-transit-gateway-multicast-domain \
--transit-gateway-id $TGW_ID \
--options StaticSourcesSupport=enable,Igmpv2Support=enable \
--tag-specifications 'ResourceType=transit-gateway-multicast-domain,Tags=[{Key=Name,Value=tgw-mcast-domain}]'
MCAST_DOMAIN=tgw-mcast-domain-0abc123
# Associate a VPC subnet with the multicast domain
aws ec2 associate-transit-gateway-multicast-domain \
--transit-gateway-multicast-domain-id $MCAST_DOMAIN \
--transit-gateway-attachment-id $PROD_ATTACH \
--subnet-ids subnet-0bbb111
# Register a multicast group source (the sender's ENI)
aws ec2 register-transit-gateway-multicast-group-sources \
--transit-gateway-multicast-domain-id $MCAST_DOMAIN \
--group-ip-address 239.0.0.1 \
--network-interface-ids eni-0sender123
# Register multicast group members (receivers)
aws ec2 register-transit-gateway-multicast-group-members \
--transit-gateway-multicast-domain-id $MCAST_DOMAIN \
--group-ip-address 239.0.0.1 \
--network-interface-ids eni-0recv1 eni-0recv2 eni-0recv3
ECMP for Bandwidth Scaling
Equal-Cost Multi-Path (ECMP) allows multiple VPN tunnels to a TGW to share traffic, effectively multiplying your VPN bandwidth. Each standard VPN tunnel provides up to 1.25 Gbps; with ECMP across multiple tunnels you can achieve 50 Gbps+ aggregate throughput.
ECMP is enabled with VpnEcmpSupport=enable on the TGW and requires BGP on the VPN connections (static VPN connections do not support ECMP). Your on-premises router must advertise the same prefix via all tunnels with equal BGP attributes for AWS to distribute load across them.
AWS Network Manager for Centralized Visibility
AWS Network Manager is a free management layer that gives you a global view of all your TGW-connected resources: VPCs, VPN connections, Direct Connect gateways, and on-premises networks. It builds a topology map and enables CloudWatch metrics/events for network health.
# Create a global network (one per organization)
aws networkmanager create-global-network \
--description "prod-global-network" \
--tag-specifications 'ResourceType=global-network,Tags=[{Key=Name,Value=prod-global-net}]'
GLOBAL_NET_ID=network-0abc1234
# Register your TGW with Network Manager
aws networkmanager register-transit-gateway \
--global-network-id $GLOBAL_NET_ID \
--transit-gateway-arn arn:aws:ec2:us-east-1:123456789012:transit-gateway/$TGW_ID
# Create a site to represent your on-premises data center
aws networkmanager create-site \
--global-network-id $GLOBAL_NET_ID \
--description "Mysore-DC" \
--location '{"Address":"Mysore, Karnataka, India","Latitude":"12.2958","Longitude":"76.6394"}'
SITE_ID=site-0mysore1
# Create a device representing your on-premises router
aws networkmanager create-device \
--global-network-id $GLOBAL_NET_ID \
--site-id $SITE_ID \
--description "Edge-Router-1" \
--type "router"
DEVICE_ID=device-0router1
# Associate the VPN connection with the on-premises device
aws networkmanager associate-customer-gateway \
--global-network-id $GLOBAL_NET_ID \
--customer-gateway-arn arn:aws:ec2:us-east-1:123456789012:customer-gateway/$CGW_ID \
--device-id $DEVICE_ID
Once registered, Network Manager populates a Route Analyzer tool — you can input source and destination IPs and it traces the logical path through TGW route tables, flagging black holes and misconfigurations. It also generates CloudWatch Events when tunnel status changes, making it easy to build alerting for hybrid connectivity failures.
Cost Breakdown and Optimization Tips
Transit Gateway is not free. Understanding the cost model prevents bill shock at scale.
| Charge Type | Rate (us-east-1, 2026) | Notes |
|---|---|---|
| Attachment fee | $0.05 per attachment-hour | Charged per VPC/VPN/DX attachment, per AZ |
| Data processing | $0.02 per GB | Applied to all data processed by TGW |
| Inter-region peering attachment | $0.05 per attachment-hour (per region) | Plus standard data transfer charges |
| Network Manager | Free | No charge for topology visibility |
| VPN connection | $0.05 per VPN connection-hour | In addition to TGW attachment fee |
Optimization Strategies
1. Consolidate AZ attachments. Each subnet you add to a VPC attachment is a separate attachment-hour charge per AZ. For non-critical workloads, attaching only one subnet (one AZ) halves the attachment cost, though you lose AZ redundancy for that traffic path.
2. Use centralized egress instead of per-VPC NAT Gateways. Put a NAT Gateway in your shared-services VPC and route all workload VPC internet traffic (0.0.0.0/0) through TGW to the shared NAT. NAT Gateway costs $0.045/hour plus $0.045/GB — far more expensive than TGW data processing at $0.02/GB. For 20 workload VPCs with moderate traffic, centralized egress typically saves 40–60% on NAT costs.
3. Avoid routing between VPCs that don't need to talk. Don't propagate routes between prod and dev/staging unless required. Fewer routes mean less routing complexity and may reduce data processing if you can route some traffic peer-to-peer instead.
4. Monitor with Cost Explorer resource tags. Tag every TGW attachment with team and environment tags. Use AWS Cost Explorer to break down TGW charges by attachment ID, so you can identify which VPC or VPN connection is generating the most data processing costs.
5. Consider VPC peering for static, high-volume pairs. If two VPCs consistently transfer 10+ TB/month between them, a VPC peering connection (data transfer only, no per-GB TGW processing fee) may be cheaper than routing via TGW for that specific pair, while still using TGW for everything else.
Frequently Asked Questions
Can I use Transit Gateway with AWS Organizations and RAM for cross-account sharing?
Yes. Use AWS Resource Access Manager (RAM) to share a TGW across your entire AWS Organization. Create the TGW in a network or shared-services account, share it via RAM with your organization or specific OUs, and then each workload account can create VPC attachments to the shared TGW. This avoids creating separate TGW instances per account and centralizes routing policy management. The attachment fees are charged in the account that owns the attachment, not the TGW owner account.
What happens if a TGW attachment subnet becomes unavailable?
If you have TGW ENIs in multiple AZs for a VPC attachment (recommended), traffic fails over to the remaining AZs automatically. The TGW itself is a fully managed, highly available Regional service — AWS maintains the underlying infrastructure. However, if your attachment only covers one AZ and that AZ fails, traffic from that VPC cannot route through TGW until the AZ recovers. Always attach at least two subnets in different AZs for production VPCs.
How do I implement network segmentation (e.g., prod cannot reach dev)?
Create separate TGW route tables: one for prod VPC attachments and one for non-prod. Do not propagate non-prod routes into the prod route table and vice versa. Only propagate the shared-services attachment into both tables. This gives you hard network isolation without needing Security Groups or NACLs to carry the full burden of environment separation. You can verify the isolation with aws ec2 search-transit-gateway-routes to inspect each route table.
Does Transit Gateway support IPv6?
Yes. You can enable IPv6 support on a VPC attachment by specifying IPv6 subnets. TGW route tables support both IPv4 and IPv6 prefixes simultaneously. For VPN attachments, IPv6 inside tunnel is supported with BGP. Direct Connect IPv6 requires a separate BGP peering session on the Virtual Interface. ECMP and multicast work with IPv6 as well.
Can I inspect all TGW traffic with a firewall appliance?
Yes — this is the "security VPC" or "inspection VPC" pattern. Create a security VPC with AWS Network Firewall or a third-party NGFW appliance, attach it to the TGW, and add a static default route (0.0.0.0/0) in all workload VPC route tables pointing to the TGW, with a corresponding route in the TGW route table sending that traffic to the security VPC attachment. East-west inspection (VPC-to-VPC) requires a bump-in-the-wire design with separate inbound and outbound TGW route tables — this is called the "appliance mode" design and requires enabling ApplianceModeSupport=enable on the security VPC attachment to ensure symmetric routing.