Skip to main content

Terraform Ep 4: Input Variables, Outputs, and Data Types

Rachmat Hidayat
Author
Rachmat Hidayat
Learn & sharing insights on TypeScript, Go, Kubernetes, DevOps, DevSecOps, SRE, Platform Engineering, AI/ML Engineering, and MLOps.
terraform - This article is part of a series.
Part 4: This Article
If you hardcode IP addresses and environment names directly into your resource blocks, you are writing rigid scripts, not robust Infrastructure as Code. Let’s parameterize your infrastructure so the exact same code can deploy both your Staging and Production environments.

1. The Core Concept: Input Variables
#

Think of a Terraform configuration directory as a mathematical function. Input Variables are the arguments you pass into the function, and the physical cloud resources are the result.

By utilizing Input Variables, you separate your logic (the resource blocks) from your configuration (the specific names, sizes, and CIDR blocks).

Declaring a Variable
#

Variables are declared using the variable block. You should typically place all your variables in a dedicated file named variables.tf.

# variables.tf

variable "instance_type" {
  description = "The EC2 instance size (e.g., t3.micro)"
  type        = string
  default     = "t3.micro"
}

variable "environment_name" {
  description = "The name of the environment (e.g., staging, prod)"
  type        = string
  # Notice there is no default here. This makes the variable REQUIRED.
}

Using a Variable
#

To inject the variable into your resource blocks, you use the var. prefix.

# main.tf

resource "aws_instance" "web_server" {
  ami           = "ami-1234567890"
  
  # Injecting the variables dynamically
  instance_type = var.instance_type
  
  tags = {
    Name = "${var.environment_name}-web-server"
  }
}

2. Deep Dive: HCL Data Types
#

Terraform is strongly typed. When you declare a variable, you must explicitly state what kind of data it accepts. This acts as a strict guardrail, preventing a junior developer from passing a string (“five”) into a variable that expects an integer (5).

TypeDescriptionExample HCL Syntax
stringA sequence of Unicode characters."production"
numberWhole numbers or decimals.8080 or 3.14
boolBoolean values.true or false
list(type)An ordered sequence of the same type.["us-east-1a", "us-east-1b"]
map(type)Key-value pairs where all values are the same type.{ Environment = "Prod", Team = "DevOps" }
object({...})Complex data structures with mixed types.{ name = "John", age = 30, is_admin = true }

Practice: Advanced Data Types
#

Let’s declare a more complex variable using the object type to enforce strict schema validation:

variable "database_config" {
  description = "Configuration for the RDS database"
  type = object({
    engine         = string
    port           = number
    multi_az       = bool
    allowed_cidrs  = list(string)
  })
}

If a user tries to pass "8080" (a string) into the port field instead of 8080 (a number), Terraform will immediately throw a compilation error during the plan phase, long before any physical damage is done to AWS.


3. Feeding Values to Variables (The .tfvars File)
#

If you declare a variable without a default value, Terraform will pause execution in the terminal and interactively prompt you to type the value. This breaks CI/CD automation.

To automate the injection of values, we use a Variable Definitions file, commonly named terraform.tfvars.

Create a file named terraform.tfvars:

# terraform.tfvars
# Terraform automatically loads this file if it is named exactly terraform.tfvars

environment_name = "production"
instance_type    = "t3.large"

database_config = {
  engine        = "postgres"
  port          = 5432
  multi_az      = true
  allowed_cidrs = ["10.0.0.0/16", "192.168.1.0/24"]
}

When you run terraform plan, Terraform will automatically suck in the values from this file and inject them into the var. references in your main.tf.

Tip

Multi-Environment Architecture Strategy You can create multiple files like staging.tfvars and production.tfvars. When executing Terraform in CI/CD, you specify which file to use via the command line: terraform apply -var-file="staging.tfvars"


4. Extracting Information: Outputs
#

If Variables are the Inputs to our mathematical function, Outputs are the Return Values.

When Terraform creates a resource (like an AWS RDS Database), AWS assigns it a random endpoint URL. How do you extract that URL so your application developers can use it? You use an output block.

# outputs.tf

output "database_endpoint" {
  description = "The connection endpoint for the RDS database"
  value       = aws_db_instance.main_database.endpoint
  sensitive   = false
}

output "database_password" {
  description = "The master password (masked in terminal)"
  value       = aws_db_instance.main_database.password
  sensitive   = true
}

When you run terraform apply, Terraform will print these exact values to your terminal at the very end of the execution:

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

Outputs:

database_endpoint = "main-database.c3x9z...us-east-1.rds.amazonaws.com"
database_password = <sensitive>

(Notice how the sensitive = true flag prevents the password from being leaked in plain text on your CI/CD console logs).


Troubleshooting & Common Errors
#

  1. Value for undeclared variable

    • Root Cause: You defined a value in your terraform.tfvars file, but you forgot to declare the corresponding variable {} block in variables.tf.
    • Solution: Every variable passed via a .tfvars file MUST have a corresponding declaration block.
  2. Invalid value for variable

    • Root Cause: You violated the strong typing system. For example, you passed a string where a list(string) was expected.
    • Solution: Check the type definition in your variables.tf and ensure the data in your .tfvars file matches the exact schema structure.
  3. Reference to undeclared input variable

    • Root Cause: You tried to use var.my_variable in main.tf, but it was never declared.
    • Solution: Ensure the variable is declared in variables.tf. Check for typos.

Conclusion & Next Steps
#

You have successfully decoupled your configuration data from your infrastructure logic. By mastering Variables, Data Types, and .tfvars files, your Terraform codebase is now highly dynamic, reusable, and ready for multi-environment deployments.

However, what if you need to reference an AWS Subnet that was created by another team, and you don’t know its ID?

In Episode 5: Querying Existing Cloud Infrastructure with Data Sources, we will learn how to interrogate the cloud provider’s API to fetch real-time information about resources that Terraform did not create!

terraform - This article is part of a series.
Part 4: This Article