DEV Community

Udoh Deborah
Udoh Deborah

Posted on

Day 69 : Meta Arguments in Terraform

A. two ready-to-run Terraform examples (one count demo, one for_each demo),

B. step-by-step instructions to run and inspect results,

C. a clear explanation of meta-arguments and best practices, and (D) cleanup & cost warnings. Replace (AMI, region, key name, etc.) before running.

  • Quick safety note: the AWS EC2 examples will create real instances that can incur cost. If you only want to experiment without charges, use the local_file or null_resource variants (I include a lightweight local demo below).

A — Example 1 — count (create N identical resources)

Purpose: create N identical resources (same config). Use count when you want a number of identical copies.

Create folder day69-count/ and files:

main.tf

terraform {
  required_providers {
    aws = { source = "hashicorp/aws" version = "~> 5.0" }
  }
}
provider "aws" {
  region = var.region
}

resource "aws_instance" "server" {
  count         = var.instance_count
  ami           = var.instance_ami
  instance_type = var.instance_type
  key_name      = var.key_name

  tags = {
    Name = "server-${count.index}"
  }
}
Enter fullscreen mode Exit fullscreen mode

variables.tf

variable "region" {
  type    = string
  default = "us-east-1"
}

variable "instance_count" {
  type    = number
  default = 2
}

variable "instance_ami" {
  type    = string
  default = "ami-08c40ec9ead489470" # replace for your region
}

variable "instance_type" {
  type    = string
  default = "t2.micro"
}

variable "key_name" {
  type = string
  default = "<YOUR_KEY_PAIR>"
}
Enter fullscreen mode Exit fullscreen mode

outputs.tf

output "instance_ids" {
  value = aws_instance.server[*].id
}
output "instance_public_ips" {
  value = aws_instance.server[*].public_ip
}
Enter fullscreen mode Exit fullscreen mode

Run:

terraform init
terraform plan -out plan.tfplan
terraform apply "plan.tfplan"
Enter fullscreen mode Exit fullscreen mode

Inspect addresses / outputs:
• Resources created are referenced as aws_instance.server[0], aws_instance.server[1], etc.
• count.index inside the block gives the zero-based index.

Change count:
• Update var.instance_count = 4 (or pass -var="instance_count=4"), run terraform apply — Terraform will create additional instances for indices 2 and 3.

B — Example 2 — for_each (create resources with distinct values)

Purpose: multiple similar resources which have different attributes (AMIs, names, or other per-item configuration). Use for_each with a map or set-of-strings so each instance is keyed and stable.

Create folder day69-foreach/ and files:

main.tf

terraform {
  required_providers {
    aws = { source = "hashicorp/aws" version = "~> 5.0" }
  }
}
provider "aws" {
  region = var.region
}

# map of named instances -> ami
variable "servers_map" {
  type = map(string)
  default = {
    "linux"  = "ami-0b0dcb5067f052a63"
    "ubuntu" = "ami-08c40ec9ead489470"
  }
}

resource "aws_instance" "server" {
  for_each      = var.servers_map
  ami           = each.value
  instance_type = var.instance_type
  key_name      = var.key_name

  tags = {
    Name = "server-${each.key}"
  }
}

Enter fullscreen mode Exit fullscreen mode

variables.tf

variable "region" {
type = string
default = "us-east-1"
}
variable "instance_type" {
type = string
default = "t2.micro"
}
variable "key_name" {
type = string
default = ""
}


Enter fullscreen mode Exit fullscreen mode

outputs.tf

output "server_public_ips" {
value = { for k, r in aws_instance.server : k => r.public_ip }
}


Run: same terraform init && terraform apply.

Inspect addresses / outputs:
    • Resources are referenced by key: e.g. aws_instance.server["linux"], aws_instance.server["ubuntu"].
    • each.key and each.value available inside the block.

Change for_each map:
    • Add or remove keys in servers_map then terraform apply. Terraform will create or destroy only the specific keyed resources — stable mapping reduces accidental replacements.



C — Lightweight demo (no AWS charges) — use local_file and null_resource

If you want to learn semantics without creating cloud resources, try this local demo:

Folder day69-local/:

main.tf

Enter fullscreen mode Exit fullscreen mode

resource "local_file" "count_files" {
count = 3
filename = "${path.module}/count_file_${count.index}.txt"
content = "file created with count index ${count.index}"
}

locals {
items = {
"one" = "first"
"two" = "second"
}
}

resource "local_file" "foreach_files" {
for_each = local.items
filename = "${path.module}/foreach_${each.key}.txt"
content = "for_each created ${each.key} => ${each.value}"
}


Run terraform init && terraform apply — you’ll get files in your folder; no cloud cost.



D — Meta-arguments: what they are & how to use them

Meta-arguments are special arguments accepted by resource/module blocks that control Terraform language behavior. Common meta-arguments include:
• count — number of instances (integer). Addresses use numeric indices: resource.type.name[index].
• for_each — iterate over a map or set; produces one instance per key. Addresses use keys: resource.type.name["key"].
• depends_on — explicit dependency list (useful in rare cases).
• provider — select which provider configuration to use.
• lifecycle — control create_before_destroy, prevent_destroy, ignore_changes.
• provisioner — (discouraged for most cases) run local/remote commands.

Count vs For_each — when to use which
• Use count:
• When you just need N identical copies.
• When order/indices are fine and attributes are identical.
• Example: count = 4 to create 4 identical web servers.
• Use for_each:
• When each instance needs unique attributes (different AMIs, names, sizes).
• When you want stable resource identity across changes (keys are stable).
• Use a map if you need key→value pairs (each.key and each.value).
• Use a set of strings if only names/IDs are needed.

Addressing differences
• count → aws_instance.foo[0], aws_instance.foo[1]
• for_each → aws_instance.foo["linux"], aws_instance.foo["ubuntu"]

State & lifecycle implications
• Changing count may cause Terraform to destroy the highest indexed resources if you reduce the number — which can be destructive.
• for_each keyed resources are more stable when adding/removing different keys.
• If you convert from count → for_each or vice versa, Terraform will typically want to recreate resources (state address changes). Use terraform state mv to migrate state safely if needed.

Tips & best practices
• Prefer for_each (map) for heterogeneous resources or when identity matters.
• Use toset() or tolist() conversions to ensure predictable input types.
• Avoid dynamic index assumptions; don’t depend on count.index to persist a machine’s identity over time.
• Keep resource blocks small and idempotent.
• Use lifecycle { create_before_destroy = true } when replacing resources that affect availability (but be careful).
• For large fleets, consider modules to group repeated logic and pass counts/for_each into module blocks.



E — Example: multiple key/value iteration (map with structured attributes)

If instances need multiple attributes:

Enter fullscreen mode Exit fullscreen mode

variable "servers" {
default = {
web1 = { ami = "ami-aaa", instance_type = "t3.micro" }
web2 = { ami = "ami-bbb", instance_type = "t2.micro" }
}
}

resource "aws_instance" "web" {
for_each = var.servers
ami = each.value.ami
instance_type = each.value.instance_type
tags = { Name = each.key }
}




This is powerful — each.key becomes your stable identifier.



F — How to demonstrate for an interview (suggested steps)
1. Show the count example: instance_count = 2 apply, then change to 4 and apply — show terraform plan then apply.
2. Show the for_each example: add a new map key and terraform apply — point out only that key’s resource is created.
3. Show terraform state list and how addresses look (aws_instance.server[0] vs aws_instance.server["linux"]).
4. Explain migration: demonstrate terraform state mv if you rename keys or move from count→for_each.
5. Discuss real-world choice: use for_each for stable identity (e.g., DB replicas with different roles), count for identical worker nodes when identity is irrelevant (but note the stability issues).



G — Cleanup & cost control
• For AWS examples: terraform destroy -auto-approve to remove resources.
• Always confirm what will be destroyed with terraform plan -destroy.
• Use small instance types (e.g., t3.micro) and a single AZ for demos, or use local_file demo to avoid charges.
Enter fullscreen mode Exit fullscreen mode

Top comments (0)