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.

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.

FeatureVPC PeeringAWS PrivateLinkTransit Gateway
Traffic modelPeer-to-peer (1:1)Service-to-consumer (1:N)Hub-and-spoke (N:N)
Transitive routingNoNoYes
Connections required for 10 VPCs45 peering connectionsN/A (service-based)10 attachments to 1 TGW
Cross-region supportYes (inter-region peering)No (same-region only)Yes (TGW peering)
Bandwidth limitUp to 50 Gbps per pair10 Gbps per ENIUp to 50 Gbps per AZ (ECMP)
On-premises connectivityNoNoYes (VPN + Direct Connect)
Overlapping CIDRsNot supportedSupported (NLB-based)Not supported natively
Cost modelData transfer onlyPer-hour + dataPer-hour + data per GB
Best forSimple 2-3 VPC connectivitySharing a service across many consumersLarge multi-VPC and hybrid networks
Rule of thumb: Use VPC peering when you have 4 or fewer VPCs that need full mesh. Use PrivateLink when you want to expose a single service (e.g., an internal API) to multiple consumers without sharing the entire network. Use Transit Gateway for everything else — especially when you have a hybrid on-premises connection to share across VPCs.

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.

Important: You must also add a route in each VPC's subnet route table pointing the destination CIDR to the TGW attachment. TGW handles the hub routing; VPC route tables handle the spoke routing.

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
Key options explained: Setting 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
BGP over VPN: AWS recommends using dynamic BGP routing rather than static routes for VPN attachments. BGP automatically propagates your on-premises prefixes into TGW route tables and sends your VPC CIDRs back to your router. This eliminates manual route maintenance and provides faster failover between tunnels.

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
Allowed Prefixes: When associating a DXGW with a TGW, you must explicitly declare which VPC CIDRs to advertise over the DX circuit. AWS will not advertise all propagated routes automatically — you control the prefix list. Keep this list accurate to avoid routing holes.

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
Note: Inter-region TGW peering uses static routes only — BGP propagation does not work across peering attachments. You must manually add routes in both regions. Plan your CIDR allocation carefully so you can summarize routes efficiently (e.g., us-east-1 owns 10.0.0.0/8, ap-south-1 owns 172.16.0.0/12).

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 TypeRate (us-east-1, 2026)Notes
Attachment fee$0.05 per attachment-hourCharged per VPC/VPN/DX attachment, per AZ
Data processing$0.02 per GBApplied to all data processed by TGW
Inter-region peering attachment$0.05 per attachment-hour (per region)Plus standard data transfer charges
Network ManagerFreeNo charge for topology visibility
VPN connection$0.05 per VPN connection-hourIn 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.

Estimated monthly cost example: 10 VPC attachments × 2 AZs × $0.05 × 730 hours = $730 in attachment fees. Plus $0.02/GB for data processed. For 10 TB/month across all attachments, add $204. Total ≈ $934/month — compare this to the operational overhead of managing 45 VPC peering connections with static routes.

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.