An extra 30% off every course until Sunday, October 11.Choose your certification →

Copyright (c) 2026 MindMesh Academy. All rights reserved. This content is proprietary and may not be reproduced or distributed without permission.

4.4.1. Complex Types

💡 First Principle: Type constraints catch mistakes early and document intent — declaring a variable as map(string) means Terraform rejects a list before anything is created, turning a runtime surprise into a clear configuration error.

Terraform types fall into three groups. Primitives: string, number, bool. Collection types (all elements the same type): list(...), set(...) (unordered, unique), map(...). Structural types (mixed element types): object({...}) (named attributes with types) and tuple([...]) (ordered, per-position types). There's also any (no constraint).

TypeShapeExample
list(string)Ordered, duplicates allowed["a", "b", "a"]
set(string)Unordered, unique["a", "b"]
map(number)Key→value, keys unique{ a = 1, b = 2 }
object({...})Named attributes, mixed types{ name = "x", size = 3 }
tuple([...])Ordered, fixed per-position types["x", 3, true]

Instance identity: count vs for_each. count produces a list of instances addressed by zero-based index (aws_instance.web[0]) — even with count = 1 you index it — so removing an element from the middle of the driving list shifts every later index, and Terraform plans changes to those instances to match their new positions. for_each keys each instance by a map key or set member (aws_instance.web["us-east-1a"]), so adding or removing one key touches only that instance; prefer it whenever items come and go. for_each accepts only a map or a set of strings: wrap a list in toset(), which — like any conversion to a set(...) type — silently drops duplicates and order. Lists and tuples are addressed by zero-based position (var.zones[0] is the first element); only maps and objects are addressed by key or attribute name.

⚠️ Exam Trap: Know list vs set: a list is ordered and allows duplicates; a set is unordered and deduplicates. This matters for for_each (which needs a set or map of unique keys) versus count (which uses a list/number by index).

Reflection Question: Why is for_each typically used with a set or map rather than a list?

See how it connects
Alvin Varughese
Written byAlvin Varughese
Founder•20 professional certifications