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

Abdul AzeemAbdul Azeem
2 min read

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:

  1. You define variables inside the module – this tells Terraform what the module expects.

  2. In the root module (your environment folder), you:

    • Declare those same variables.

    • Provide values through terraform.tfvars, environment variables, or directly.

  3. 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!

1
Subscribe to my newsletter

Read articles from Abdul Azeem directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Abdul Azeem
Abdul Azeem