Beginner's Guide To Terraform's Try Function

Andrei Dumitrescu
Andrei Dumitrescu
hero image

Handling unexpected scenarios in Terraform can feel like navigating a maze, especially if you’re just starting out. But what if there was a way to make your configurations more resilient and avoid frustrating failures?

Well good news, because that’s exactly what the try function does! It’s like having a safety net for your Terraform plans, ensuring they run smoothly even when something goes wrong.

In this guide, you’ll discover what the try function is, why it’s a game-changer, and how to use it to create error-proof configurations. So that by the end, you’ll have the tools to handle Terraform challenges with confidence.

Let's get started…

Sidenote: Want to dive deeper into learning and using Terraform? Then check out my DevOps Bootcamp for Terraform.

DevOps Terraform Bootcamp

Updated for 2025, I cover everything from the fundamentals all the way to provisioning real-world cloud infrastructure on AWS. You can go from total beginner to being able to get hired as a DevOps Engineer or System Administrator, so it’s a great resource for any skill level.

With that out of the way, let’s get into this 5-minute tutorial…

What is the try function in Terraform and why use it?

When working with Terraform, you’ll often encounter inputs or configurations that might not behave as expected, such as a missing variable, an invalid value, or a resource that doesn’t return data.

Normally, these kinds of issues would cause your configuration to fail, forcing you to troubleshoot and fix them manually. That’s where the try function steps in. It’s a built-in tool designed to catch errors before they can disrupt your setup, ensuring Terraform keeps running smoothly.

Here’s how it works:

The try function evaluates multiple expressions in order and returns the first one that doesn’t produce an error. If none of the expressions succeed, it throws an error, giving you visibility into what went wrong. By doing this, try not only saves you time but also simplifies how you handle edge cases and optional inputs.

Think of it as an automatic fallback system. Instead of writing complex conditional logic for every possible failure, you can provide a list of options, and Terraform will choose the first valid one. This makes your code cleaner, more maintainable, and less prone to errors.

Here’s the syntax:

try(expression1, expression2, ..., expressionN)

Here's how it works:

  • Terraform evaluates each expression from left to right
  • As soon as it finds a valid result, it stops and returns that value
  • If none of the expressions succeed, it throws an error

As you can imagine, this makes your life a lot easier. Especially when you consider that Terraform configurations often deal with variables or resources that don’t always behave as expected.

Optional variables might not be set, resources could fail to return data, or multi-cloud setups might require juggling different attributes for the same concept. Without a way to handle these uncertainties, your configurations risk becoming error-prone and brittle.

The try function solves this problem by letting you define fallback values for invalid inputs, missing resources, or provider-specific variations.

I’ll show you some examples of these in action later, but lets break these down quickly so you get the idea.

You can use the try function to handle optional variables

In shared modules or multi-environment setups, some inputs—like a region variable—might not always be provided. However, instead of breaking your setup, the try function ensures there’s always a fallback value to keep your configuration functional.

It gets better though.

You can use the try function to provide fallback values for dynamic resources

Dynamic resources, such as querying for the latest AMI in AWS, might not always return data.

For example

If no AMIs match your criteria, your configuration could fail. But by using the try function, you can supply a fallback value and ensure your setup stays operational.

And you can even use the try function to adapt to multi-cloud differences

When deploying across multiple cloud providers, resource attributes often differ. AWS uses instance_type for EC2 instances, while Azure uses vm_size.

The good news?

Instead of having to write complex conditional logic, the try function lets you handle these differences gracefully by checking for available attributes and falling back to a default when necessary.

Tl;DR

The try function is incredibly handy to use. You just need to make sure you use it correctly and don’t make a few common mistakes. The good news is, I'll walk you through it all now.

How to use the try function effectively

Using the try function effectively isn’t just about writing valid code—it’s about ensuring your configurations are reliable, maintainable, and resilient to unexpected issues.

By planning carefully, writing clear logic, and testing thoroughly, you can handle errors gracefully and avoid unnecessary troubleshooting later.

Speaking of planning, that brings me to step #1.

Step #1. Plan your configuration

Before you start writing Terraform code, it’s important to map out how your try function will handle potential issues.

  • What values might fail? Identify inputs or resources that could return invalid data, such as optional variables that aren’t set or resource queries that might return null
  • What fallback values make sense? Fallbacks should ensure your setup behaves predictably. A default like "us-west-1" for a region is clear and functional, whereas "unknown" could lead to confusion or unintended outcomes. This principle applies not only to missing variables but also to dynamic resources or multi-cloud setups where defaults ensure stability

For example: Planning for a missing region variable

Suppose some teams using your module forget to set the region variable. You can plan for this by providing a default:

variable "region" {
  default = null
}

output "selected_region" {
  value = try(var.region, "us-west-1")
}

Tip: Always choose meaningful fallback values that align with your infrastructure’s goals. This keeps your configurations clear and intentional.

Why a final fallback is critical

Without a final fallback, Terraform throws an error if all expressions fail:

# Without a fallback, this will fail
value = try(null, null)

To avoid this, make sure every try function ends with a valid fallback:

value = try(null, null, "default_value")

Taking the time to plan ahead saves you from troubleshooting later and ensures your configurations handle edge cases gracefully.

Step #2. Write your try configuration

Once you’ve planned for potential issues and chosen meaningful fallback values, it’s time to put try into action. The key is to write configurations that are both functional and easy to maintain.

Let’s explore a few common use cases and issues to watch out for.

Using optional variables

Optional variables are a frequent scenario where try shines. Instead of letting a missing value cause errors, you can specify a fallback:

output "selected_region" {
  value = try(var.region, "us-west-1")
}

It’s tempting to cram as much logic as possible into a single try function, but this can quickly make your code harder to read and debug. So instead, break your logic into smaller, manageable components:

variable "primary_value" {
  default = null
}

variable "secondary_value" {
  default = "fallback"
}

output "example_output" {
  value = try(var.primary_value, var.secondary_value, "default_value")
}

Using Dynamic resources

Dynamic resources, like AMIs, don’t always return data. Not only that, but Dynamic resources often change based on external conditions.

The good news is that using try ensures your configuration remains stable, even when unexpected issues arise. So instead of letting your configuration fail, you can use try to set a fallback:

data "aws_ami" "example" {
  most_recent = true
  owners  	= ["self"]
}

output "ami_id" {
  value = try(data.aws_ami.example.id, "ami-12345678")
}

Watch out for this mistake: Mixing data types in your try function will cause Terraform to throw an error. All expressions must return the same type:

# Incorrect: Mixing string and number types
value = try("string", 123)

To avoid this, ensure all expressions are consistent:

value = try("string", "fallback_string")

Handling multi-cloud setups

When deploying across multiple cloud providers, you’ll often encounter differing attributes for similar resources.

For example

AWS uses instance_type, while Azure uses vm_size. Instead of writing separate conditional logic for each provider, try lets you handle these variations seamlessly:

output "cloud_instance_type" {
  value = try(
	aws_instance.example.instance_type,
	azurerm_virtual_machine.example.vm_size,
	"default-instance-type"
  )
}

Final note on writing your try configuration

You won’t face these situations every time, but when you do, the try function is your safety net. It helps you handle the unexpected without overcomplicating your setup.

Now, let’s move on to testing your configuration to make sure everything runs exactly as planned.

Step #3. Test your configuration

Testing ensures your configuration can handle anything Terraform throws its way, from missing inputs to invalid data. Without proper testing, what works in development might fail spectacularly in production.

The best approach? Start small with isolated tests, then scale up to validate try’s behavior in more complex scenarios. Here’s how you can systematically test your configurations for complete confidence.

Test for valid inputs

Let’s start simple. Set your variables to valid values and check that try selects the correct one:

variable "primary_value" {
  default = "custom"
}

If this works, then our expected output here will be: "custom".

Dealing with invalid inputs

Next, let’s test a scenario where things don’t go as planned. If the input is null, does try fall back to the next value?

variable "primary_value" {
  default = null
}

output "example_output" {
  value = try(var.primary_value, "fallback_value")
}

Your output here should be "fallback_value". That’s exactly what you’d expect, and try makes it effortless.

Simulate total failure

Now for the big test—what happens if everything fails? Remove all valid inputs to check if Terraform throws a meaningful error:

output "example_output" {
  value = try(null, null)
}

The result? Terraform will return an error message, letting you know no valid value was found. This is where testing saves you from production headaches.

Test across environments

Once you’re confident in your local testing, it’s time to verify that your configuration behaves consistently across staging, production, and other environments.

This ensures that fallback logic isn’t broken by differences in resource availability or environment-specific configurations.

**For example **

Imagine you’re deploying a module that references storage buckets. In staging, the bucket might be optional, while in production, it’s required. Without proper fallback logic, the deployment could fail or provision resources incorrectly.

By testing, you can:

  • Ensure the correct storage bucket is referenced in each environment
  • Simulate missing inputs to confirm fallback behavior (e.g., creating a default bucket if none exists)
  • Compare outputs across environments to catch discrepancies early

TL;DR

Testing across valid, invalid, and edge-case scenarios gives you complete confidence in your configuration. It’s like stress-testing your setup to see how it holds up.

That being said though, testing is only part of the process. So once you know everything behaves correctly, it’s time to refine and document your setup for long-term maintainability.

Step #4. Refine and document your configuration

This step not only improves clarity for others (and your future self) but also ensures your code remains maintainable as your infrastructure evolves.

Tools like Terraform’s terraform-docs can save you hours by automating documentation. Using these tools ensures your fallback logic and configuration decisions are clear to anyone working with your code.

Simplify where possible

When your fallback logic is straightforward, simpler alternatives like coalesce or lookup might be a better fit than try. These functions focus on specific use cases and are easier to read:

output "better_logic" {
  value = coalesce(var.optional_value, "fallback_value")
}

However, for complex fallback chains, stick with try to maintain flexibility without over complicating your configuration.

Document decisions

Good documentation can save hours of debugging down the road, so make sure to include comments that explain:

  • Why you chose specific fallback values (e.g., making a note that "us-west-1" aligns with a specific regional redundancy) would help someone understand the relevance and help catch any errors
  • What happens in edge cases (e.g., when all expressions fail)

For example

# Use primary_value if set; fallback to secondary_value, or "default_value" if both are null
output "example_output" {
  value = try(var.primary_value, var.secondary_value, "default_value")
}

Give try a try yourself now!

The try function in Terraform is more than just a way to handle errors—it’s your toolkit for building smarter, cleaner, and more resilient configurations. By following these steps, you can:

  • Handle missing or invalid inputs without disrupting your setup
  • Simplify complex conditional logic, making your code easier to maintain
  • Adapt to unexpected scenarios, whether you’re working with optional variables, dynamic resources, or multi-cloud environments

Your challenge: Try using the try function in a small Terraform project, like an S3 bucket, and test different inputs. Start small, test thoroughly, and watch as your configurations become more resilient.

P.S.

Don’t forget! If you want to dive deeper into learning and using Terraform, check out my DevOps Bootcamp for Terraform.

DevOps Terraform Bootcamp

I cover everything from the fundamentals all the way to provisioning real-world cloud infrastructure on AWS and getting hired!

Once you join, you'll have the opportunity to ask questions in our private Discord community from me, other students and working professionals.


Not only that, but as a member - you’ll also get access to every course in the Zero To Mastery library!

More from Zero To Mastery

53 Terraform Interview Questions and Answers preview
53 Terraform Interview Questions and Answers

About to sit for a DevOps technical interview with Terraform? Learn the most common questions and answers that you need to know to ace your interview!

Beginner’s Guide to Dynamic Blocks in Terraform (With Code Examples) preview
Beginner’s Guide to Dynamic Blocks in Terraform (With Code Examples)

Learn how to use Terraform dynamic blocks to automate repetitive tasks, streamline infrastructure, and scale efficiently in this step-by-step guide.

Beginner’s Guide to the for_each Meta-Argument in Terraform preview
Beginner’s Guide to the for_each Meta-Argument in Terraform

Discover the secret to efficient resource management! Learn how to use the for_each meta-argument to streamline your Terraform configurations today.