Day 11 of my 30-Day Terraform Challenge was all about going deeper into conditionals in Terraform.
Yesterday I used conditionals briefly alongside loops, but today the focus was entirely on how conditionals make Terraform configurations more flexible, reusable, and environment-aware.
This was one of the most practical Terraform days so far because it showed how a single codebase can behave differently in development and production without duplication.
Why Conditionals Matter in Terraform
Without conditionals, it is very easy to end up maintaining multiple copies of similar infrastructure code.
For example, you might create:
- one version for development
- another for staging
- another for production
That quickly becomes hard to maintain.
Conditionals solve this by allowing Terraform to make decisions at plan time and apply time based on input variables and local values.
That means one configuration can support multiple use cases while staying clean and reusable.
The Ternary Expression
The core Terraform conditional is the ternary expression.
It follows this pattern:
- if condition is true → use one value
- otherwise → use another value
I used this pattern to make my infrastructure behave differently depending on the environment.
Instead of scattering conditional logic directly inside resource arguments, I moved all the decisions into a locals block.
That made the module much easier to read and much easier to maintain.
Why Centralizing Logic in locals Matters
One of the most useful lessons from today was learning that locals are the right place for conditional decisions.
I used locals to control:
- instance type
- minimum cluster size
- maximum cluster size
- whether monitoring is enabled
- environment-specific behavior
This made my module cleaner because the resources themselves stayed focused on infrastructure, while the locals block handled the logic.
That separation is important when your Terraform grows beyond small examples.
Conditional Resource Creation with count
One of the most powerful Terraform patterns I practiced today was:
count = condition ? 1 : 0
This is how you make an entire resource optional.
I used this for resources such as:
- CloudWatch alarms
- Route53 records
This pattern is very useful because some resources should only exist in specific environments or use cases.
For example:
- production might need monitoring
- development might not
- DNS records might only be created when explicitly requested
This pattern lets Terraform create or skip resources based on simple boolean toggles.
Referencing Conditional Resources Safely
A very important lesson today was that conditionally created resources cannot be referenced like normal resources.
If a resource uses count, then Terraform treats it like a list.
That means if the count is zero, there is no resource at index [0].
So if you reference it directly without checking whether it exists, Terraform throws an error.
The correct pattern is to guard the reference with another conditional so Terraform only tries to read the resource when it was actually created.
This is one of those details that seems small until it breaks your plan.
Building an Environment-Aware Module
The most practical part of today’s work was making my webserver cluster module fully environment-aware.
I used a single input variable:
environment
That one variable then controlled multiple infrastructure decisions.
In development:
- smaller instance type
- smaller cluster size
- monitoring disabled
In production:
- larger instance type
- larger cluster size
- monitoring enabled
This was a really good example of how one Terraform module can behave like multiple infrastructure configurations without duplicating code.
That is exactly the kind of pattern that becomes valuable in real teams.
Input Validation: Catching Errors Early
Another feature I added today was an input validation block.
This made sure that only valid environment names could be used, such as:
devstagingproduction
If someone passed an invalid value, Terraform returned a clear error before any infrastructure was deployed.
This is such a useful pattern because it helps catch mistakes early and prevents confusing downstream issues.
It is a small addition, but it makes a module much safer to share and reuse.
Conditional Data Sources: Existing vs New Infrastructure
One of the most interesting patterns from today was using conditionals with data sources.
I used this to support two deployment styles:
Brownfield deployment
Use an existing VPC
Greenfield deployment
Create a new VPC
This was controlled with a simple boolean toggle.
That pattern makes a module much more flexible because it can work in environments where infrastructure already exists, as well as in environments where everything needs to be created from scratch.
That is a very realistic real-world use case.
Challenges I Faced
One of the key things I had to be careful with today was making sure conditionally created resources were referenced safely.
Without the proper guards, Terraform would throw index errors when trying to access a resource that did not exist.
I also had to make sure my validation logic only accepted the intended environment values and behaved correctly when testing invalid input.
These were not huge blockers, but they were useful reminders that Terraform logic has to be designed carefully, especially when conditions affect whether resources exist at all.
What I Learned from Day 11
Today helped me understand the difference between:
- conditional expressions → choosing between values
- conditional resource creation → deciding whether a resource exists at all
That distinction is very important.
I also learned that conditionals become much more powerful when combined with:
locals- validation
- optional resources
- data sources
- environment-aware design
This made Terraform feel much more like writing reusable infrastructure logic rather than just declaring resources one by one.
Final Thoughts
Day 11 was one of the most practical and useful Terraform challenge days so far.
It showed me how to write Terraform that is:
- cleaner
- more flexible
- easier to reuse
- safer across environments
Most importantly, it showed how one Terraform configuration can support multiple environments and deployment patterns without needing multiple codebases.
That is a huge step toward writing production-ready Infrastructure as Code.
Connect With Me
I’m documenting my journey through the 30-Day Terraform Challenge as I continue learning more about:
- Terraform
- AWS
- Infrastructure as Code
- DevOps best practices
If you are also learning cloud or IaC, feel free to connect.
Top comments (0)