DEV Community

Stephanie Makori
Stephanie Makori

Posted on

Mastering Loops and Conditionals in Terraform

Day 10 of my 30-Day Terraform Challenge was all about making Terraform configurations more dynamic, scalable, and less repetitive.

Until now, most of my Terraform resources were declared one by one. That works for small labs, but it quickly becomes inefficient when you need multiple similar resources. Today’s focus was on the features that solve that problem:

  • count
  • for_each
  • for expressions
  • conditional logic

These are the Terraform features that make Infrastructure as Code feel much closer to programming.


Why This Matters

When working with infrastructure, repetition becomes a problem very quickly.

If you need:

  • multiple IAM users
  • repeated security group resources
  • optional scaling policies
  • different environment-specific configurations

…copy-pasting resource blocks is not a good long-term solution.

Terraform’s looping and conditional tools help make configurations:

  • more reusable
  • easier to maintain
  • safer to update
  • more scalable

That is exactly what I worked on today.


Using count

The simplest loop in Terraform is count.

It is useful when you want to create N copies of the same resource.

For my lab, I used count to create multiple IAM users from a list.

This worked well for creating a fixed number of users and helped me understand how count.index works.

What count.index Does

count.index gives the numeric position of the resource currently being created.

So if I have three usernames in a list:

  • index 0 → first user
  • index 1 → second user
  • index 2 → third user

This makes count very straightforward.

The Problem with count

The downside is that Terraform tracks these resources by position, not by identity.

That means if I remove an item from the middle of the list, Terraform shifts the indexes of everything after it.

As a result, resources can be unexpectedly recreated even if their names did not logically change.

This is one of those Terraform behaviors that can easily surprise you if you do not know how resource indexing works.


Using for_each

for_each solves the biggest weakness of count.

Instead of tracking resources by numeric position, Terraform tracks them by a key or value.

That means resources are more stable when the input collection changes.

For today’s challenge, I used for_each in two ways:

  • with a set
  • with a map

for_each with a Set

This is useful when you just need unique values, such as usernames.

Terraform creates one resource per value.

for_each with a Map

This is more powerful because it lets each resource carry its own extra configuration.

For example, each IAM user could have:

  • a department
  • an admin status

This made the configuration more descriptive and closer to a real-world use case.

Why for_each Is Safer

If I remove one user from a for_each collection, Terraform only removes that specific resource.

It does not renumber the rest of them.

That makes it much safer than count for collections that may change over time.


Using for Expressions

for expressions are different from count and for_each.

They do not create resources.

Instead, they are used to transform data.

For this challenge, I used a for expression in an output to create a clean map of IAM user ARNs keyed by username.

This was useful because it turned raw Terraform resource data into a much more readable and reusable structure.

I liked this part because it made outputs feel more intentional and structured rather than just dumping raw values.


Using Conditional Logic

Terraform conditionals use a ternary-style pattern:

  • if condition is true → use one value
  • otherwise → use another value

I used conditionals in two practical ways today.

1. Optional Autoscaling

I added an enable_autoscaling variable to my webserver cluster module.

When it is set to true, Terraform creates the autoscaling policies.

When it is set to false, Terraform skips them.

This is a great example of how conditionals can make infrastructure optional without duplicating code.

2. Environment-Based Instance Sizing

I also used conditional logic to vary instance size by environment.

This meant:

  • dev could use a smaller instance
  • production could use a larger instance

That is a realistic pattern and something I would absolutely expect to see in a real deployment.


Refactoring My Existing Infrastructure

The most useful part of today’s challenge was applying these ideas to infrastructure I had already built.

I refactored my webserver-cluster module from previous challenge days and improved it using what I learned.

What I Changed

I updated my module to:

  • replace repeated resource patterns with for_each
  • use count for optional autoscaling policies
  • use locals to centralize environment-based logic
  • use a for expression in outputs to create cleaner maps

This made the module much more reusable and much easier to maintain.

That is one of the biggest things I am starting to appreciate with Terraform: a lot of the improvement is not about adding more resources, but about writing infrastructure more intelligently.


A Challenge I Ran Into

One issue I hit during the for_each lab was accidentally trying to create duplicate IAM usernames in two different resource blocks.

Terraform returned an EntityAlreadyExists error because IAM usernames must be unique.

That problem was not really about Terraform syntax — it was about understanding how the configuration behaved as a whole.

I fixed it by changing the usernames in one of the collections so there was no overlap.

That was a useful reminder that infrastructure logic still needs careful thinking, even when the syntax is correct.

I also hit a temporary provider registry connection issue during terraform init, but retrying resolved it.


My Verdict: count vs for_each

After today, my takeaway is this:

Use count when:

  • you need a fixed number of almost identical resources
  • indexing is acceptable
  • you want a simple optional toggle pattern

Use for_each when:

  • resources are tied to meaningful names or keys
  • the collection may change over time
  • you want more stable infrastructure behavior

So while count is still useful, I would generally choose for_each for anything that is likely to evolve.


Key Lessons from Day 10

Today taught me that Terraform becomes much more powerful when you stop thinking in terms of static resource blocks and start thinking in terms of:

  • collections
  • transformations
  • reusable logic
  • controlled optional behavior

That shift makes Terraform feel much more expressive and much more maintainable.


Final Thoughts

Day 10 was one of the most practical challenge days so far.

It was not just about learning new syntax — it was about learning how to write better Terraform.

I now have a much clearer understanding of:

  • when to use count
  • when to use for_each
  • how to use for expressions
  • how to make infrastructure conditional and environment-aware

These are the kinds of patterns that make Infrastructure as Code more maintainable in real projects.


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.

Terraform #IaC #AWS #DevOps #CloudComputing #30DayTerraformChallenge #TerraformChallenge #InfrastructureAsCode

Top comments (0)