1. count
- Create Multiple Similar Resources
Creates multiple instances of a resource based on a numeric value.
# Basic count usage
resource "azurerm_storage_queue" "test_queues" {
count = var.env == "qa" ? 2 : 0
name = "test-queue-${count.index}"
storage_account_name = azurerm_storage_account.example.name
}
# Conditional resource creation
resource "aws_instance" "web" {
count = var.create_instances ? 3 : 0
ami = "ami-12345678"
instance_type = "t2.micro"
tags = {
Name = "web-server-${count.index}"
}
}
Key Points:
count.index
provides the current iteration index (0, 1, 2…)- Resources become arrays:
aws_instance.web[0]
,aws_instance.web[1]
- Changing count can cause resource destruction/recreation
2. for_each
- Create Resources from Map/Set
Creates resources based on a map or set of strings, more flexible than count.
# Using set of strings
resource "azurerm_eventgrid_system_topic_event_subscription" "vm_events" {
for_each = toset(["qa", "qa-test", "prod"])
name = "vm-lifecycle-events-${each.key}"
system_topic = var.system_topic_name
storage_queue_endpoint {
queue_name = "vmlifecycle-events-${each.key}"
}
}
# Using map
variable "environments" {
default = {
qa = { instance_type = "t2.micro", count = 1 }
prod = { instance_type = "t2.medium", count = 3 }
}
}
resource "aws_instance" "app" {
for_each = var.environments
ami = "ami-12345678"
instance_type = each.value.instance_type
tags = {
Environment = each.key
Name = "app-${each.key}"
}
}
Key Points:
each.key
= current map key or set elementeach.value
= current map value (not available for sets)- Resources referenced as:
aws_instance.app["qa"]
- More stable than count for adding/removing resources
IMPORTANT
Use ‘for_each’ instead of ‘count’ when possible. It’s more flexible and stable.
3. depends_on
- Explicit Dependencies
Forces Terraform to create resources in specific order, beyond automatic dependency detection.
resource "azurerm_resource_group" "example" {
name = "eventgrid-${var.env}"
location = "West US 2"
}
resource "azurerm_eventgrid_system_topic" "resources" {
name = "resource-events-${var.env}"
resource_group_name = azurerm_resource_group.example.name
# Explicit dependency (usually not needed due to automatic detection)
depends_on = [azurerm_resource_group.example]
}
# More complex dependency
resource "null_resource" "app_deployment" {
depends_on = [
aws_instance.web,
aws_db_instance.database,
aws_security_group.app_sg
]
provisioner "local-exec" {
command = "./deploy-app.sh"
}
}
When to Use:
- When there are hidden dependencies Terraform can’t detect
- Where ther are dependencies between modules
- Ordering provisioners or null_resource actions
NOTE
This is useful when the dependency across module boundaries is not obvious.
4. provider
- Specify Resource Provider
Selects which provider configuration to use when you have multiple providers.
# Configure multiple AWS providers
provider "aws" {
alias = "us_east_1"
region = "us-east-1"
}
provider "aws" {
alias = "us_west_2"
region = "us-west-2"
}
# Use specific provider
resource "aws_instance" "east" {
provider = aws.us_east_1
ami = "ami-12345678"
instance_type = "t2.micro"
}
resource "aws_instance" "west" {
provider = aws.us_west_2
ami = "ami-87654321"
instance_type = "t2.micro"
}
5. lifecycle
- Control Resource Lifecycle
Controls how Terraform handles resource creation, updates, and deletion.
resource "aws_instance" "example" {
ami = "ami-12345678"
instance_type = "t2.micro"
lifecycle {
# Prevent accidental deletion
prevent_destroy = true
# Create new before destroying old
create_before_destroy = true
# Ignore changes to specific attributes
ignore_changes = [
ami, # Ignore AMI updates
tags["Date"] # Ignore specific tag changes
]
# Conditional lifecycle rules
precondition {
condition = var.env != "prod" || var.instance_type != "t2.nano"
error_message = "Production instances cannot use t2.nano."
}
postcondition {
condition = self.public_ip != ""
error_message = "Instance must have a public IP."
}
}
}
Lifecycle Options:
prevent_destroy
- Blockterraform destroy
create_before_destroy
- Create replacement before destroyingignore_changes
- Ignore changes to specified attributesreplace_triggered_by
- Force replacement when referenced resources changeprecondition
/postcondition
- Validation checks
NOTE
Generally for simple lifecycle controls. Good side: it is supported by all resources.