aws_main_route_table_association cost estimation
Sets which route table is the main (default) table for a VPC. The association is free, but it decides the default path for any subnet without an explicit table, and that path can silently route traffic through paid NAT or transit gateways.
The aws_main_route_table_association resource changes which route table serves as the main route table for a VPC. Every VPC has exactly one main route table, and any subnet that is not explicitly associated with another table falls back to it. This association is free, AWS charges nothing for designating or changing the main route table.
Its cost relevance is subtle but real: the main route table is the default for unassociated subnets, so its contents decide where their traffic goes. If the main table contains a 0.0.0.0/0 route pointing at a NAT gateway or transit gateway, then every subnet you create without wiring an explicit route table inherits that paid path automatically. This is a common source of unexpected data processing charges: a developer adds a subnet, forgets to associate a route table, and its outbound traffic quietly flows through the NAT gateway at 0.045 dollars per GB.
A widely recommended safety pattern is to keep the main route table minimal, containing only the local VPC route and no path to the internet or a NAT gateway, and to explicitly associate every subnet with a purpose-built public or private route table. That way a forgotten association fails closed (no internet access) rather than failing open into a billable NAT path. aws_main_route_table_association lets you point the main association at exactly the table you intend rather than the default one AWS created with the VPC.
Because the association only selects a table, the actual cost still comes from the routes in that table and the targets they reference. A main table pointing at a NAT gateway inherits the NAT hourly charge (about 32 dollars per month) plus per-GB processing for all traffic from subnets that use it; a main table with only the local route costs nothing to traverse.
c3x reports aws_main_route_table_association as free and attributes any spend to the NAT gateway, transit gateway, or peering targets that the associated table routes traffic through.
Terraform example
A minimal but realistic configuration that C3X can estimate.
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
}
# A deliberately minimal table: only the implicit local route, no NAT or IGW.
resource "aws_route_table" "restricted_default" {
vpc_id = aws_vpc.main.id
tags = { Name = "vpc-main-restricted" }
}
# Make the restricted table the main one so unassociated subnets fail closed.
resource "aws_main_route_table_association" "main" {
vpc_id = aws_vpc.main.id
route_table_id = aws_route_table.restricted_default.id
}Pricing dimensions
What you actually pay for when you provision aws_main_route_table_association.
| Dimension | Unit | What's being charged |
|---|---|---|
| Main route table association | free | Designating or changing the main route table is a free control-plane operation. $0 (free) |
| NAT gateway (if the main table routes to one) | per hour + per GB processed | If the main table has a default route to a NAT gateway, unassociated subnets inherit its charges. $0.045/hour (~$32/month) + $0.045 per GB processed |
| Transit gateway (if the main table routes to one) | per attachment-hour + per GB | A main-table route to a transit gateway bills every inherited subnet's traffic for data processing. $0.05 per attachment-hour + $0.02 per GB processed |
Optimization tips
Common ways to reduce aws_main_route_table_association cost without changing the workload.
Keep the main route table minimal so subnets fail closed
Point the main association at a table containing only the local VPC route. A subnet you forget to associate then has no internet or NAT path and fails closed, rather than silently routing through a paid NAT gateway.
Explicitly associate every subnet with a purpose-built table
Do not rely on the main table for real routing. Give each subnet an explicit public or private route table so its cost path is intentional and visible in code, not inherited by default.
Audit what the main table routes to before adding subnets
Before scaling out subnets, confirm the main table's default route. If it points at a NAT or transit gateway, every new unassociated subnet inherits that per-GB charge.
Use gateway endpoints in the associated table for S3 and DynamoDB
$0.045 per GB of S3/DynamoDB traffic kept off NATIf the associated table carries data-heavy traffic, add free gateway VPC endpoint routes so S3 and DynamoDB traffic bypasses the NAT gateway and avoids per-GB processing.
FAQ
Does the main route table association cost anything?
No. Choosing which route table is the main one for a VPC is free. Any cost comes from the routes inside that table and the NAT gateway, transit gateway, or peering targets they point at.
Why does the main route table matter for cost?
It is the default table for any subnet you do not explicitly associate with another. If it contains a route to a NAT or transit gateway, forgotten subnets inherit that paid path and quietly generate per-GB data processing charges.
What is the safe default configuration?
Make the main table minimal with only the local VPC route, and explicitly associate every subnet with a purpose-built public or private table. A forgotten subnet then has no internet path and fails closed instead of billing through NAT.
How is this different from aws_route_table_association?
aws_route_table_association links a specific subnet to a specific table. aws_main_route_table_association sets the VPC-wide default table used by any subnet without an explicit association. Both are free; the difference is scope.
Related resources
Estimate this resource in your own Terraform
Free, open source, no API key. C3X parses your Terraform and shows line-item cost for every resource, including aws_main_route_table_association.