Working with Expressions
1. Writing String Expressions
| Expression Type | Description | Example |
|---|---|---|
| String Concatenation | Joining strings using the + operator | "Hello " + "World" |
| String Interpolation | Inserting variable values into strings using ${} |
"Hello ${var.name}" |
| Template Functions | Functions for string manipulation like upper(), lower() |
upper("hello") |
Example: String Concatenation
resource "aws_instance" "web" {
ami = data.aws_ami.ubuntu.id
instance_type = "t2.micro"
tags = {
Name = "WebServer-" + var.environment
}
}
Example: String Interpolation
output "instance_name" {
value = "Instance ${aws_instance.web.id} is running"
}
2. Using Arithmetic Operators (+, -, *, /)
| Operator | Description | Example | Result |
|---|---|---|---|
| + | Addition | 5 + 3 |
8 |
| - | Subtraction | 10 - 4 |
6 |
| * | Multiplication | 6 * 7 |
42 |
| / | Division | 20 / 4 |
5 |
Example: Basic Arithmetic in Variables
variable "length" {
type = number
default = 10
}
variable "width" {
type = number
default = 5
}
output "area" {
value = var.length * var.width
}
3. Using Comparison Operators (==, !=, <, >)
| Operator | Description | Examples | Notes |
|---|---|---|---|
| == | Equal to | var.age == 25 |
Compares values for equality |
| != | Not equal to | var.name != "John" |
Compares values for inequality |
| < | Less than | var.count < 10 |
Checks if the left operand is less than the right operand |
| > | Greater than | var.price > 50.0 |
Checks if the left operand is greater than the right operand |
| <= | Less than or equal to | var.value <= 100 |
Checks if the left operand is less than or equal to the right operand |
| >= | Greater than or equal to | var.score >= 80 |
Checks if the left operand is greater than or equal to the right operand |
Example: Using Comparison Operators in Conditions
resource "aws_instance" "web" {
ami = "ami-12345678"
instance_type = var.instance_type
tags = {
Name = "web-server"
Env = var.environment
}
# Conditionally set instance type based on environment
instance_type = var.environment == "production" ? "t3.large" : "t3.medium"
}
4. Using Logical Operators (&&, ||, !)
| Operator | Description | Example | Result |
|---|---|---|---|
| ! | Logical NOT operator | !true |
false |
| && | Logical AND operator | true && false |
false |
| || | Logical OR operator | true || false |
true |
Example: Combining Conditions
resource "aws_instance" "web" {
count = var.enable_web_server && var.web_instance_type != ""
instance_type = var.web_instance_type
ami = var.ami_id
}
Example: Negating Conditions
resource "aws_s3_bucket" "logs" {
bucket = "my-logs-bucket"
force_destroy = !var.retention_policy_enabled
}
5. Using Conditional Expressions (condition ? true : false)
| Expression | Description | Example |
|---|---|---|
| condition ? true_value : false_value | Conditional expression that evaluates to one of two values based on a boolean condition | var.enabled ? "production" : "staging" |
Example: Conditional Resource Creation
resource "aws_instance" "web" {
count = var.create_web_instance ? 1 : 0
ami = "ami-12345678"
instance_type = var.instance_type
}
Example: Conditional Variable Assignment
variable "environment" {
default = "staging"
}
locals {
region = var.environment == "production" ? "us-west-2" : "us-east-1"
}
Note: The ternary operator in Terraform is a powerful way to conditionally assign values or create resources. It's particularly useful for managing different configurations across environments.
6. Using For Expressions ([for item in list])
For expressions in Terraform allow you to iterate over collections and transform them into different data structures. The basic syntax is:
[for item in list : transformation]
Example: Transforming a List of Numbers
numbers = [for n in [1, 2, 3, 4] : n * 2]
# Result: [2, 4, 6, 8]
| Expression | Description | Result |
|---|---|---|
| [for item in list : item] | Identity transformation | [1, 2, 3] |
| [for item in list : item * 2] | Transforms each item | [2, 4, 6] |
| [for item in list : item if item > 2] | Filters items | [3, 4] |
Note: The
for expression can also be used to build maps and sets, not just lists.
Example: Building a Map from a List
map_example = {
for item in ["a", "b", "c"] :
item => upper(item)
}
# Result: { a = "A", b = "B", c = "C" }
7. Using Splat Expressions (resource.*.attribute)
Splat expressions provide a concise way to access attributes from all instances of a resource or data source in Terraform.
| Expression | Description | Example Usage |
|---|---|---|
resource.name.attribute |
Accesses the specified attribute from all instances of a resource | aws_instance.web.*.public_ip |
data.name.attribute |
Accesses the specified attribute from all instances of a data source | data.aws_subnet.subnet.*.cidr_block |
Example: Accessing Public IPs from Multiple Instances
resource "aws_instance" "web" {
count = 3
ami = "ami-12345678"
instance_type = "t2.micro"
}
output "public_ips" {
value = aws_instance.web.*.public_ip
}
Note: The splat operator returns a list of values, even if there is only one instance. If you expect a single value, consider using
aws_instance.web[0].public_ip instead.
Example: Using Splat in a Variable
variable "instance_ips" {
type = list(string)
default = aws_instance.web.*.public_ip
}
8. Accessing Map and Object Attributes
| Expression | Description | Example | Result |
|---|---|---|---|
| map.key | Access a value in a map using a key | local.my_map.key1 |
value1 |
| object.attribute | Access an attribute in an object | local.my_object.attr1 |
value1 |
| map["key"] | Access a value in a map using bracket notation | local.my_map["key1"] |
value1 |
| object["attribute"] | Access an attribute in an object using bracket notation | local.my_object["attr1"] |
value |
Example: Accessing Map Attributes
locals {
server_config = {
name = "web-server"
port = 80
environment = "production"
}
}
output "server_name" {
value = local.server_config.name
}
Example: Accessing Object Attributes with Bracket Notation
locals {
server_config = {
name = "web-server"
port = 80
environment = "production"
}
}
output "server_port" {
value = local.server_config["port"]
}
9. Using String Templates
Terraform supports string templates using the templatefile() function, which allows you to embed variables and expressions into template files.
| Function | Description | Example |
|---|---|---|
| templatefile() | Reads a template file and renders it with provided variables | templatefile("config.tmpl", { name = "example", port = 8080 }) |
Example: Using templatefile()
resource "aws_instance" "web" {
ami = data.aws_ami.ubuntu.id
instance_type = "t2.micro"
user_data = templatefile("user-data.sh.tmpl", {
instance_name = "web-server"
port = 80
})
}
Example: Template file (user-data.sh.tmpl)
#!/bin/bash
echo "Starting web server on port ${port}"
sudo systemctl start nginx
Template files can include expressions and variable interpolations, making them powerful for generating dynamic configuration.
Note: Template files must be valid HCL or shell script syntax depending on their usage context.
10. Understanding Type Constraints
| Type | Description | Examples | Notes |
|---|---|---|---|
| string | Textual data | "hello" |
Must be enclosed in quotes |
| number | Numeric values | 42, 3.14 |
Can be integers or floats |
| bool | Boolean values | true, false |
Case-sensitive |
| list(<type>) | Ordered collection of elements | ["a", "b", "c"] |
Elements must be of same type |
| set(<type>) | Unordered collection of unique elements | ["a", "b", "c"] |
Elements must be of same type |
| map(<type>) | Map of key-value pairs | {"key1": "value1", "key2": "value2"} |
Values must be of same type |
| object({attr1 = type, ...}) | Structured object with named attributes | {name = "John", age = 30} |
Attributes must match specified types |
| tuple([type1, type2, ...]) | Ordered list with fixed size | [1, "hello", true] |
Each element can have different type |
Example: Type Constraints in Variables
variable "server_config" {
type = object({
name = string
port = number
active = bool
})
default = {
name = "web-server"
port = 80
active = true
}
}
Example: Type Constraints in Outputs
output "server_ips" {
value = [for instance in aws_instance.server : instance.private_ip]
type = list(string)
}
Note: Type constraints are enforced at runtime during evaluation, not compile-time.
11. Using Null Values
| Expression | Description | Notes |
|---|---|---|
| null | null is a special value in Terraform that represents the absence of a value. |
It's often used to conditionally exclude attributes or blocks from being applied. |
| can be used in: | Conditional expressions, variable assignments, and function arguments. | When a value is null, it can be ignored or skipped in certain contexts. |
Example: Using null in conditional expressions
resource "aws_instance" "example" {
ami = var.ami_id
instance_type = var.instance_type
# Only set tags if they are provided
tags = var.tags == null ? {} : var.tags
}
Note: Using
null in expressions can help avoid errors when optional values are not provided, especially in modules or configurations that support optional parameters.