TF-004 for_each Practice Question
An organization uses Terraform modules to provision multiple environments. They have a module 'vpc' that uses a for_each argument in the root module to create VPCs per environment. Each VPC requires a unique CIDR block passed via variable. What is the best practice to pass different CIDRs per instance?
⚠ Common exam trap
The most common trap is to use `count` with a list and `element()` instead of `for_each` with a map. While both can work, `for_each` with a map is preferred because it creates a clear association between the key (environment name) and the value (CIDR), making the configuration more readable and less error-prone.
Answer choices
Why each option matters
Answer the question above first, then reveal the full breakdown to understand why each option is right or wrong.
Correct answer & explanation
✓
Define a map variable with environment names as keys and CIDRs as values, then pass the entire map to the module.
Using a map variable with environment names as keys and CIDRs as values allows Terraform's `for_each` to iterate over the map, creating one VPC per environment with its specified CIDR. This approach is clear, scalable, and maintains a direct key-value association. Option B (hardcoding) is not scalable and violates infrastructure as code best practices. Option C uses `count.index` and `element()` on a list, which works but is less explicit and can lead to errors if list order changes. Option D is irrelevant because module outputs are read after creation and cannot be used to define input CIDRs.
Answer analysis
Option-by-option breakdown
For each option: why learners choose it and why it is or isn't the right answer here.
- ✓
Define a map variable with environment names as keys and CIDRs as values, then pass the entire map to the module.
Why this is correct
This approach is ideal for provisioning multiple module instances, especially when using `for_each` on the module block. By defining a map variable, each key (e.g., "dev", "prod") can represent a distinct environment, and its corresponding value (the CIDR) can be passed directly to that specific module instance. This method ensures clear association, promotes reusability, and allows for dynamic scaling and configuration of environments without modifying the module's source code. It aligns perfectly with Terraform's declarative nature for managing distinct, yet similar, infrastructure components.
- ✗
Hardcode the CIDR within each module block.
Why it's wrong here
Hardcoding CIDR values directly within each module block severely limits the reusability and maintainability of the Terraform configuration. If an organization provisions multiple environments, each requiring a unique CIDR, repeating these values across numerous module instances creates a brittle setup. Any change to a CIDR would necessitate manual updates in multiple locations, increasing the risk of errors and making the infrastructure difficult to manage and scale. This practice directly contradicts the principles of Infrastructure as Code.
- ✗
Use a list variable for CIDRs and reference them with count.index and element().
Why it's wrong here
Using a list variable with `count.index` and `element()` is incompatible with the `for_each` argument specified in the scenario. `for_each` iterates over a map or set, exposing `each.key` and `each.value`, whereas `count.index` is specific to resources or modules configured with `count`. This option is tempting because it is a valid pattern for assigning unique values when creating multiple instances using `count`, where resources are indexed numerically rather than by distinct keys.
- ✗
Use a module output to fetch the CIDR from a data source.
Why it's wrong here
This option misinterprets the purpose of both module outputs and data sources in this context. Data sources are designed to read information about existing infrastructure or external services, not to generate or parameterize *new* input values for module instances. While a module output can expose values from within a module, it cannot dynamically fetch a unique CIDR from a data source to then feed as an *input* to *another* instance of the *same* module during its initial provisioning. Module inputs define what the module *creates*, not what it *reads* to create itself.
Visual reference
Go deeper
Related to this question
About these practice questions
One of 428 original TF-004 practice questions on Courseiva, each with a full explanation and wrong-answer analysis — not exam dumps or protected exam content. Learn why practice questions differ from exam dumps →
JA
Written by Johnson Ajibi, MSc IT Security
Senior Network & Security Engineer · founder of Courseiva
This TF-004 practice question is part of Courseiva's free HashiCorp certification practice question bank. Courseiva provides original exam-style practice questions with explanations, topic-based practice, mock exams, readiness tracking, and study analytics to help learners prepare for the TF-004 exam.