Settings for some resources can be defined inline or as standalone resources. In this article, we will see how they behave differently.
For settings like routes for route table or security group rules for security group, you have options to config them inline or as standalone resources. Let’s use routes for demonstration. In the following code, I have 2 route tables, each with several routes. rt1 is managed with inline routes, while rt2’s routes are set with standalone aws_route resources.
locals {
route-dest = toset([
"192.168.10.1/32",
"192.168.10.2/32",
"192.168.10.3/32"
])
}
resource "aws_route_table" "rt1" {
vpc_id = "vpc-01234567890123456"
dynamic "route" {
for_each = local.route-dest
content {
cidr_block = route.value
gateway_id = "igw-01234567890123456"
}
}
}
resource "aws_route_table" "rt2" {
vpc_id = "vpc-01234567890123456"
}
resource "aws_route" "rt2-routes" {
for_each = local.route-dest
route_table_id = aws_route_table.rt2.id
destination_cidr_block = each.value
gateway_id = "igw-01234567890123456"
}
Both of them works and there is little difference for the initial resource creation. But the challenge comes when you need to modify the routes later on. Suppose I now want to add one more route, say adding 192.168.20.1/32. I do that by adding the cidr block to local.route-dest. When I run terraform plan, I see that for rt1, terraform removes all existing routes and then add them back. For rt2, a new aws_route resource is created for the new address and existing routes are left alone.
The way terraform handles rt1 can be a bit of an issue. If the routes are essential to production traffic, you don’t want them removed even for less than a second. Especially when the removal is technically unnecessary. If you have numerous routes and the new route exceeds the service quota, terraform apply will fail. You now need to come up with a fix, fast. We don’t want to be in that situation.
Inline settings are convenient and the code is lean. But if you are managing your resources with terraform continuously, use standalone resources.
Below is the terraform plan for adding 1 additional route for 192.168.20.1/32.
Terraform will perform the following actions:
# aws_route.rt2-routes["192.168.20.1/32"] will be created
+ resource "aws_route" "rt2-routes" {
+ destination_cidr_block = "192.168.20.1/32"
+ gateway_id = "igw-01234567890123456"
+ id = (known after apply)
+ instance_id = (known after apply)
+ instance_owner_id = (known after apply)
+ network_interface_id = (known after apply)
+ origin = (known after apply)
+ route_table_id = "rtb-05e8665817bf302ac"
+ state = (known after apply)
}
# aws_route_table.rt1 will be updated in-place
~ resource "aws_route_table" "rt1" {
id = "rtb-0ad32e3201e3f123f"
~ route = [
- {
- carrier_gateway_id = ""
- cidr_block = "192.168.10.1/32"
- core_network_arn = ""
- destination_prefix_list_id = ""
- egress_only_gateway_id = ""
- gateway_id = "igw-01234567890123456"
- ipv6_cidr_block = ""
- local_gateway_id = ""
- nat_gateway_id = ""
- network_interface_id = ""
- transit_gateway_id = ""
- vpc_endpoint_id = ""
- vpc_peering_connection_id = ""
},
- {
- carrier_gateway_id = ""
- cidr_block = "192.168.10.2/32"
- core_network_arn = ""
- destination_prefix_list_id = ""
- egress_only_gateway_id = ""
- gateway_id = "igw-01234567890123456"
- ipv6_cidr_block = ""
- local_gateway_id = ""
- nat_gateway_id = ""
- network_interface_id = ""
- transit_gateway_id = ""
- vpc_endpoint_id = ""
- vpc_peering_connection_id = ""
},
- {
- carrier_gateway_id = ""
- cidr_block = "192.168.10.3/32"
- core_network_arn = ""
- destination_prefix_list_id = ""
- egress_only_gateway_id = ""
- gateway_id = "igw-01234567890123456"
- ipv6_cidr_block = ""
- local_gateway_id = ""
- nat_gateway_id = ""
- network_interface_id = ""
- transit_gateway_id = ""
- vpc_endpoint_id = ""
- vpc_peering_connection_id = ""
},
+ {
+ carrier_gateway_id = ""
+ cidr_block = "192.168.20.1/32"
+ core_network_arn = ""
+ destination_prefix_list_id = ""
+ egress_only_gateway_id = ""
+ gateway_id = "igw-01234567890123456"
+ ipv6_cidr_block = ""
+ local_gateway_id = ""
+ nat_gateway_id = ""
+ network_interface_id = ""
+ transit_gateway_id = ""
+ vpc_endpoint_id = ""
+ vpc_peering_connection_id = ""
},
+ {
+ carrier_gateway_id = null
+ cidr_block = "192.168.10.1/32"
+ core_network_arn = null
+ destination_prefix_list_id = null
+ egress_only_gateway_id = null
+ gateway_id = "igw-01234567890123456"
+ ipv6_cidr_block = null
+ local_gateway_id = null
+ nat_gateway_id = null
+ network_interface_id = null
+ transit_gateway_id = null
+ vpc_endpoint_id = null
+ vpc_peering_connection_id = null
},
+ {
+ carrier_gateway_id = null
+ cidr_block = "192.168.10.2/32"
+ core_network_arn = null
+ destination_prefix_list_id = null
+ egress_only_gateway_id = null
+ gateway_id = "igw-01234567890123456"
+ ipv6_cidr_block = null
+ local_gateway_id = null
+ nat_gateway_id = null
+ network_interface_id = null
+ transit_gateway_id = null
+ vpc_endpoint_id = null
+ vpc_peering_connection_id = null
},
+ {
+ carrier_gateway_id = null
+ cidr_block = "192.168.10.3/32"
+ core_network_arn = null
+ destination_prefix_list_id = null
+ egress_only_gateway_id = null
+ gateway_id = "igw-01234567890123456"
+ ipv6_cidr_block = null
+ local_gateway_id = null
+ nat_gateway_id = null
+ network_interface_id = null
+ transit_gateway_id = null
+ vpc_endpoint_id = null
+ vpc_peering_connection_id = null
},
]
tags = {}
# (5 unchanged attributes hidden)
}
Plan: 1 to add, 1 to change, 0 to destroy.
![]()