• HashiCorp Developer

  • HashiCorp Cloud Platform
  • Terraform
  • Packer
  • Consul
  • Vault
  • Boundary
  • Nomad
  • Waypoint
  • Vagrant
Terraform
  • Install
  • Tutorials
    • About the Docs
    • Configuration Language
    • Terraform CLI
    • Terraform Cloud
    • Terraform Enterprise
    • CDK for Terraform
    • Provider Use
    • Plugin Development
    • Registry Publishing
    • Integration Program
  • Registry(opens in new tab)
  • Try Cloud(opens in new tab)
  • Sign up
Configuration Language

Skip to main content
18 tutorials
  • Define Infrastructure with Terraform Resources
  • Perform CRUD Operations with Providers
  • Customize Terraform Configuration with Variables
  • Protect Sensitive Input Variables
  • Simplify Terraform Configuration with Locals
  • Output Data from Terraform
  • Query Data Sources
  • Create Resource Dependencies
  • Manage Similar Resources with Count
  • Manage Similar Resources with For Each
  • Perform Dynamic Operations with Functions
  • Create Dynamic Expressions
  • Lock and Upgrade Provider Versions
  • Troubleshoot Terraform
  • Manage Terraform Versions
  • Use Configuration to Move Resources
  • Validate Modules with Custom Conditions
  • Customize Modules with Object Attributes

  • Resources

  • Tutorial Library
  • Certifications
  • Community Forum
    (opens in new tab)
  • Support
    (opens in new tab)
  • GitHub
    (opens in new tab)
  • Terraform Registry
    (opens in new tab)
  1. Developer
  2. Terraform
  3. Tutorials
  4. Configuration Language
  5. Create Dynamic Expressions

Create Dynamic Expressions

  • 11min

  • TerraformTerraform

The Terraform configuration language supports complex expressions to allow you to compute or generate values for your infrastructure configuration. Expressions can be simple string or integer values, or more complex values to make your configuration more dynamic.

In this tutorial, you will use expressions to configure and deploy EC2 instances and a load balancer. You will use conditionals to determine whether to provision multiple instances for high-availability and the splat expression to return multiple private IPs in your network.

Prerequisites

You can complete this tutorial using the same workflow with either Terraform OSS or Terraform Cloud. Terraform Cloud is a platform that you can use to manage and execute your Terraform projects. It includes features like remote state and execution, structured plan output, workspace resource summaries, and more.

Select the Terraform Cloud tab to complete this tutorial using Terraform Cloud.

This tutorial assumes that you are familiar with the Terraform workflow. If you are new to Terraform, complete the Get Started tutorials first.

In order to complete this tutorial, you will need the following:

  • Terraform v1.1+ installed locally.
  • An AWS account with local credentials configured for use with Terraform.

This tutorial assumes that you are familiar with the Terraform and Terraform Cloud workflows. If you are new to Terraform, complete the Get Started tutorials first. If you are new to Terraform Cloud, complete the Terraform Cloud Get Started tutorials first.

In order to complete this tutorial, you will need the following:

  • Terraform v1.1+ installed locally.
  • An AWS account.
  • A Terraform Cloud account with Terraform Cloud locally authenticated.
  • A Terraform Cloud variable set configured with your AWS credentials.

Clone example repository

Clone the Learn Terraform Expressions repository, which contains configuration for AWS network components, an EC2 instance, and load balancer. You will modify the configuration of these resources using Terraform expressions.

$ git clone https://github.com/hashicorp/learn-terraform-expressions.git

Navigate to the repository in your terminal.

$ cd learn-terraform-expressions

Use a conditional expression

Conditional expressions select a value based on whether the expression evaluates to true or false.

In this configuration, you will use the locals block to create a resource name based on a conditional value and capture that name in a map of resource tags.

Open your main.tf file and paste in the following code snippet.

main.tf
resource "random_id" "id" {
  byte_length = 8
}

locals {
  name  = (var.name != "" ? var.name : random_id.id.hex)
  owner = var.team
  common_tags = {
    Owner = local.owner
    Name  = local.name
  }
}

The syntax of a conditional expression first defines the condition, then the outcomes for true and false evaluations. In this example, if var.name is not empty (!= ""), local.name is set to the var.name value; otherwise, the name is the random_id.

Condition?true value:false value
If the name variable is NOT emptythenAssign the var.name value to the local valueelseAssign random_id.id.hex value to the local value

Next, update the network resources of your configuration and add the local.common_tags expression to your tags attribute.

Note: Use local values with caution. While reusing a local value simplifies your configuration, it can add complexity to your resource lifecycle.

main.tf
resource "aws_vpc" "my_vpc" {
  cidr_block           = var.cidr_vpc
  enable_dns_support   = true
  enable_dns_hostnames = true
  tags                 = local.common_tags
}

resource "aws_internet_gateway" "igw" {
  vpc_id = aws_vpc.my_vpc.id
  tags   = local.common_tags
}

resource "aws_subnet" "subnet_public" {
  vpc_id     = aws_vpc.my_vpc.id
  cidr_block = var.cidr_subnet
  tags       = local.common_tags
}

resource "aws_route_table" "rtb_public" {
  vpc_id = aws_vpc.my_vpc.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.igw.id
  }
  tags = local.common_tags
}

Update your ELB resource with the tags.

main.tf
## ...
resource "aws_elb" "learn" {
## ...
  instances                   = aws_instance.ubuntu.id
  idle_timeout                = 400
  connection_draining         = true
  connection_draining_timeout = 400
  tags                        = local.common_tags
}

Finally, update your aws_instance resource.

main.tf
resource "aws_instance" "ubuntu" {
  availability_zone = "us-east-1a"
  ami                         = data.aws_ami.ubuntu.id
  instance_type               = "t2.micro"
  associate_public_ip_address = true
  subnet_id                   = aws_subnet.subnet_public.id
  tags                        = local.common_tags
}

Save your changes.

Create a new file called outputs.tf and add the values for your instance tags.

outputs.tf
output "tags" {
  description = "Instance tags"
  value       = aws_instance.ubuntu.tags
}

Create infrastructure

Initialize this configuration.

$ terraform init

Initializing the backend...

Initializing provider plugins...
- Reusing previous version of hashicorp/aws from the dependency lock file
- Reusing previous version of hashicorp/random from the dependency lock file
- Installing hashicorp/aws v4.6.0...
- Installed hashicorp/aws v4.6.0 (signed by HashiCorp)
- Installing hashicorp/random v3.1.2...
- Installed hashicorp/random v3.1.2 (signed by HashiCorp)

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

Open your terraform.tf file and uncomment the cloud block. Replace the organization name with your own Terraform Cloud organization.

terraform.tf
terraform {
  cloud {
    organization = "organization-name"
    workspaces {
      name = "learn-terraform-expressions"
    }
  }
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.4.0"
    }
  }
  required_version = ">= 1.1"
}

Initialize your configuration. Terraform will automatically create the learn-terraform-expressions workspace in your Terraform Cloud organization.

$ terraform init
Initializing Terraform Cloud...
Initializing provider plugins...
- Reusing previous version of hashicorp/aws from the dependency lock file
- Installing hashicorp/aws v4.4.0...
- Installed hashicorp/aws v4.4.0 (signed by HashiCorp)
Terraform Cloud has been successfully initialized!
You may now begin working with Terraform Cloud. Try running "terraform plan" to
see any changes that are required for your infrastructure.
If you ever set or change modules or Terraform Settings, run "terraform init"
again to reinitialize your working directory.

Note: This tutorial assumes that you are using a tutorial-specific Terraform Cloud organization with a global variable set of your AWS credentials. Review the Create a Credential Variable Set for detailed guidance. If you are using a scoped variable set, assign it to your new workspace now.

Run terraform apply. Respond yes to the prompt to confirm the operation.

$ terraform apply

Terraform used the selected providers to generate the following execution plan. Resource actions are
indicated with the following symbols:
  + create

Terraform will perform the following actions:
##...
Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes
##...
Apply complete! Resources: 8 added, 0 changed, 0 destroyed.

Outputs:

tags = tomap({
  "Name" = "terraform"
  "Owner" = "hashicorp"
})

Tip: This tutorial shows the output for Terraform commands run with OSS. If you are following the Terraform Cloud workflow, the output may differ slightly but the results will be the same.

If you use Terraform Cloud to provision your resources, your workspace now displays the list of all of the resources it manages.

Terraform workspace resource overview

The Terraform outputs contain the formatted resource tags.

Create a conditional count criteria

Open variables.tf and add a new boolean variable for high availability.

variables.tf
variable "high_availability" {
  type        = bool
  description = "If this is a multiple instance deployment, choose `true` to deploy 3 instances"
  default     = true
}

Save this file.

Next, open main.tf and update the aws_instance resource to use the new high_availability variable.

First, update the count parameter with a conditional expression based on the value of var.high_availability. Then update the associate_public_ip_address parameter so that only the first instance is assigned a public IP address. Finally, merge the tags for the new instances.

main.tf
resource "aws_instance" "ubuntu" {
  count                       = (var.high_availability == true ? 3 : 1)
  ami                         = data.aws_ami.ubuntu.id
  instance_type               = "t2.micro"
  associate_public_ip_address = (count.index == 0 ? true : false)
  subnet_id                   = aws_subnet.subnet_public.id
  tags                        = merge(local.common_tags)
}
Condition?true value:false value
If var.high_availability is set to truethenCreate three aws_instance resourceselseCreate one aws_instance resource
If count.index is 0thenAssign public IPelseDo not assign public IP

Save your changes.

Use a splat expression

The aws_instance resource could now have a count value of 3. To return the private IP addresses of all of the instances, you will use a splat * expression to create an output value.

The splat expression captures all objects in a list that share an attribute. The special * symbol iterates over all of the elements of a given list and returns information based on the shared attribute you define.

Without the splat expression, Terraform would not be able to output the entire array of your instances and would only return the first item in the array.

Create a splat expression

Edit the outputs.tf file to add the new private_addresses output. This output will return the private DNS of all instances created by the aws_instance.ubuntu resource.

outputs.tf
output "private_addresses" {
  description = "Private DNS for AWS instances"
  value       = aws_instance.ubuntu[*].private_dns
}

This expression mirrors capturing a specific element in an array. If you only wanted to return the third instance IP in the array of instances, you could do that by replacing the * with 2.

The current tags output will error because there are multiple instances.

Replace the tags output block with the following first_tags output, which will return the first instance's tags.

outputs.tf
output "first_tags" {
  description = "Instance tags for first instance"
  value       = aws_instance.ubuntu[0].tags
}

Open main.tf to add the new instances to the ELB configuration.

main.tf
resource "aws_elb" "learn" {
##...
  instances                   = aws_instance.ubuntu[*].id
  idle_timeout                = 400
  connection_draining         = true
  connection_draining_timeout = 400
  tags                        = local.common_tags
}

Save your changes.

Apply your changes

Run terraform apply to provision the new instances and update your load balancer configuration. Respond yes to the prompt to confirm the operation.

$ terraform apply
random_id.id: Refreshing state... [id=NfgSYKxrorA]
aws_vpc.my_vpc: Refreshing state... [id=vpc-06e45b1a591e2b96f]
aws_internet_gateway.igw: Refreshing state... [id=igw-05972512ea18f8eb0]
aws_subnet.subnet_public: Refreshing state... [id=subnet-0f0710e956d144ac3]
aws_route_table.rtb_public: Refreshing state... [id=rtb-002b2df72a5eee2ba]
aws_instance.ubuntu[0]: Refreshing state... [id=i-08ff118d23a9cddc4]
aws_route_table_association.rta_subnet_public: Refreshing state... [id=rtbassoc-0d692f2cd308ef864]
aws_elb.learn: Refreshing state... [id=Learn-ELB]

Terraform used the selected providers to generate the following execution plan. Resource actions are
indicated with the following symbols:
  + create
  ~ update in-place

Terraform will perform the following actions:
##...
Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes
##...

Apply complete! Resources: 2 added, 1 changed, 0 destroyed.

Outputs:

first_tags = tomap({
  "Name" = "terraform"
  "Owner" = "hashicorp"
})
private_addresses = [
  "ip-172-16-10-133.us-east-2.compute.internal",
  "ip-172-16-10-244.us-east-2.compute.internal",
  "ip-172-16-10-63.us-east-2.compute.internal",
]

Terraform's output now contains the entire array of private addresses for all three EC2 instances.

Clean up resources

After verifying that the resources were deployed successfully, run terraform destroy to destroy them. Respond yes to the confirmation prompt to confirm the action.

$ terraform destroy
random_id.id: Refreshing state... [id=NfgSYKxrorA]
aws_vpc.my_vpc: Refreshing state... [id=vpc-06e45b1a591e2b96f]
aws_internet_gateway.igw: Refreshing state... [id=igw-05972512ea18f8eb0]
aws_subnet.subnet_public: Refreshing state... [id=subnet-0f0710e956d144ac3]
aws_route_table.rtb_public: Refreshing state... [id=rtb-002b2df72a5eee2ba]
aws_instance.ubuntu[0]: Refreshing state... [id=i-08ff118d23a9cddc4]
aws_instance.ubuntu[1]: Refreshing state... [id=i-0f4ef22bcf35a2632]
aws_instance.ubuntu[2]: Refreshing state... [id=i-0566759e2fd7116d7]
aws_route_table_association.rta_subnet_public: Refreshing state... [id=rtbassoc-0d692f2cd308ef864]
aws_elb.learn: Refreshing state... [id=Learn-ELB]

Terraform used the selected providers to generate the following execution plan. Resource actions are
indicated with the following symbols:
  - destroy

Terraform will perform the following actions:
##...
Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes
##...
Destroy complete! Resources: 10 destroyed.

If you used Terraform Cloud for this tutorial, after destroying your resources, delete the learn-terraform-expressions workspace from your Terraform Cloud organization.

Next steps

To learn more about how to create more complex, dynamic configuration, review the following resources:

  • Learn how to use local values to simplify your configuration.
  • Review how to use functions for computations in your configuration.
  • Explore how to customize your configuration using input variables.
 Previous
 Next

This tutorial also appears in:

  •  
    38 tutorials
    Associate Tutorial List (003)
    Study for the Terraform Associate (003) exam by following these tutorials. Login to Learn and bookmark them to track your progress. Study the complete list of study materials (including docs) in the Certification Prep guides.
    • Terraform

On this page

  1. Create Dynamic Expressions
  2. Prerequisites
  3. Clone example repository
  4. Use a conditional expression
  5. Create infrastructure
  6. Create a conditional count criteria
  7. Use a splat expression
  8. Clean up resources
  9. Next steps
Give Feedback(opens in new tab)
  • Certifications
  • System Status
  • Terms of Use
  • Security
  • Privacy
  • Trademark Policy
  • Trade Controls
  • Give Feedback(opens in new tab)