Terraform Type Constraints
Video Link: here.
Type Constraints

Terraform variables are primarily classified in two ways:
Based on Purpose (how they are used) and
Based on Value (what kind of data they hold, defined by Type Constraints).
Classification Based on Purpose
This defines the role of the data within the configuration:
Input Variables (
variableblock): These are parameters that let us customise our configuration from the outside (e.g., region, instance count, environment name).Output Values (
outputblock): These expose information about the infrastructure that has been created (e.g., public IP addresses, DNS names, resource IDs).Local Values (
localsblock): These are temporary, named expressions used internally within the module to avoid repeating complex values or calculations.
Classification Based on Value (Type Constraints)
This defines the specific data type a variable must accept. This is specified using the type argument in a variable block.
A. Primitive Types
These are simple, single-value types:
| Type | Description |
string | A sequence of Unicode characters (e.g., "us-east-1"). |
number | An integer or a floating-point value (e.g., 5, 3.14). |
bool | A boolean value, either true or false. |
B. Complex Types
These are collection types that group multiple values:
| Type | Description |
list | An ordered sequence of values, all of the same type (e.g., ["web", "app", "db"]). |
set | An unordered collection of unique values, all of the same type (e.g., ["a", "b"]). |
map | A collection of key-value pairs, where all values are of the same type (e.g., {name="server", env="dev"}). |
object | A structure with named attributes, each having its own specific type (e.g., object({ name = string, count = number })). |
tuple | An ordered, fixed-length sequence where values can be of different types (e.g., tuple([string, number, bool])). |
C. Special Types
any: Allows the variable to accept values of any type. While flexible, this reduces type safety and is generally discouraged unless necessary.null: Represents a value that is absent or undefined.
Example
1. Primitive Types
string - Text values
"environment" ">variable "environment" {
type = string
default = "dev"
}
number - Numeric values (integers or decimals)
"instance_count" ">variable "instance_count" {
type = number
description = "Number of EC2 instances to create"
}
bool - True or False
"monitoring_enabled" ">variable "monitoring_enabled" {
type = bool
default = true
}
2. Collection Types
list(type) - Ordered sequence, elements accessed by index
"cidr_block" ">variable "cidr_block" {
type = list(string)
default = ["10.0.0.0/16", "192.168.0.0/16", "172.16.0.0/16"]
}
# Access: var.cidr_block[0] → "10.0.0.0/16"
set(type) - Unordered unique values (no duplicates)
"allowed_region" ">variable "allowed_region" {
type = set(string)
default = ["us-east-1", "us-west-2", "eu-west-1"]
}
# Cannot access by index directly! Use: tolist(var.allowed_region)[0]
map(type) - Key-value pairs (keys are always strings)
"tags" ">variable "tags" {
type = map(string)
default = {
Name = "dev-EC2-Instance"
Environment = "dev"
created_by = "amal"
}
}
# Access: var.tags["Name"] → "dev-EC2-Instance"
# Or: var.tags.Name
3. Structural Types
tuple([types]) - Fixed-length sequence with specific types per position
"ingress_values" ">variable "ingress_values" {
type = tuple([number, string, number]) # ORDER MATTERS!
default = [443, "tcp", 443]
}
# Access: var.ingress_values[0] → 443 (number)
# var.ingress_values[1] → "tcp" (string)
# var.ingress_values[2] → 443 (number)
object({}) - Named attributes with specific types
"config" ">variable "config" {
type = object({
region = string,
monitoring = bool,
instance_count = number
})
default = {
region = "us-east-1"
monitoring = true
instance_count = 1
}
}
# Access: var.config.region → "us-east-1"
# var.config.monitoring → true
Usage Examples from Code
# Using list index
instance_type = var.ec2_allowed_types[1] # Gets "t3.small"
# Using object attributes
count = var.config.instance_count
region = var.config.region
monitoring = var.config.monitoring
# Using tuple values for security group rule
from_port = var.ingress_values[0] # 443
ip_protocol = var.ingress_values[1] # "tcp"
to_port = var.ingress_values[2] # 443
# Converting set to list (for index access)
region = tolist(var.allowed_region)[0]
Key Takeaways
Primitive types (
string,number,bool) = single valuesCollections (
list,set,map) = multiple values of SAME typeStructural (
tuple,object) = multiple values of DIFFERENT typeslist vs tuple: list = same type, dynamic length | tuple = mixed types, fixed length
map vs object: map = same value type | object = different value types per attribute
set quirk: Use
tolist()to access elements by index
Refer to the code here: Repo link.
Arigato!