Terraform Variables: Why You Must Declare Them in Both Modules and Root – A Developer’s Clarity Guide

When I first started modularizing infrastructure with Terraform, one question kept bugging me:
"Why do I need to declare the same variables in the root environment if I’ve already defined them inside the module?"
It felt repetitive. Unnecessary. Confusing even.
But once I understood how Terraform handles variable scoping, everything made perfect sense.
Let me walk you through it — because if you’re learning Infrastructure as Code (IaC) or building reusable Terraform modules, this is critical knowledge.
🎯 The Real Problem
Imagine this setup:
You have a module folder:
modules/vpc
You have a root environment folder:
env/test
Inside the module, you’ve defined your inputs in variables.tf
:
So naturally, you think you’re done. But Terraform throws an error when you apply from env/test
.
Why?
Because Terraform modules do not inherit variables from outside. They’re isolated.
A module is a black box — it defines what inputs it needs, but it cannot access any variable unless it’s explicitly passed to it.
🧠 Understanding Terraform's Flow
Here’s how the actual data flow works:
You define variables inside the module – this tells Terraform what the module expects.
In the root module (your environment folder), you:
Declare those same variables.
Provide values through
terraform.tfvars
, environment variables, or directly.
You pass those values into the module during the module call.
It’s like calling a function in Python:
You can’t just define vpc_cidr
inside the function. You must call it with real arguments!
📦 Example Terraform Setup
Folder Structure:
✅ Why This Pattern Matters
This may feel like duplication, but it gives you:
🔄 Reusability: One module used across multiple environments.
🧪 Testability: Easy to switch values for staging, dev, and prod.
💼 Clarity: Each module clearly documents what it expects.
🔒 Isolation: No unexpected dependencies or surprises.
📌 Key Takeaways
Modules are self-contained. They don’t know where their variables come from.
The root module connects all the dots by supplying values.
Always declare variables in both the module and root if you want a clean, multi-environment setup.
🗣️ Final Thoughts
Understanding this helped me clean up my Terraform structure, avoid bugs, and create scalable environments. If you’re moving from flat Terraform to modular setups — lock this mental model in.
Let me know if you’ve faced this too. How do you handle your variable flow across modules and environments?
Feel free to reach out or connect with me on LinkedIn — always happy to learn and grow with fellow DevOps and cloud enthusiasts!
Subscribe to my newsletter
Read articles from Abdul Azeem directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
