5.2.1. Calling Modules and Variable Scope
💡 First Principle: Variables are scoped to the module that declares them, so passing vpc_cidr = "10.0.0.0/16" in a module block isn't "setting a global" — it's binding an argument to that child's var.vpc_cidr, invisible to every other module.
When you call a module, each argument in the module block maps to an input variable the child module declares. The child uses those values internally via var.<name>. Crucially, the child cannot see the parent's variables, locals, or resources — only what's passed in. This isolation is what makes modules safely reusable: a module behaves the same no matter who calls it.
# root module
module "web" {
source = "./modules/web"
instance_type = var.web_size # parent's var becomes child's argument
}
# inside ./modules/web, the child declares: variable "instance_type" {}
⚠️ Exam Trap: Setting an argument in a module block requires the child to have declared a matching variable. Passing an argument the child doesn't declare is an error. And the parent's var.web_size and the child's var.instance_type are different variables in different scopes that happen to be connected by the call.
Reflection Question: Why is module variable isolation a feature rather than a limitation — what would break if child modules could read parent variables directly?