Variables, Data Types & tfvars
terraform-learning Hands-on Terraform configs, modules, and practice projects on GitHub.Variables
1. Variables
Variables are used to make Terraform configurations dynamic and reusable instead of hardcoding values.
Without variable:
resource "aws_instance" "backend" {
ami = "ami-123456"
instance_type = "t3.micro"
}
With variable:
variable "instance_type" {
type = string
default = "t3.micro"
}
resource "aws_instance" "backend" {
ami = "ami-123456"
instance_type = var.instance_type
}
Here:
variable "instance_type"
│
└── Variable name
var.instance_type
│ │
│ └── Variable name
└────────── Variable reference
So instead of hardcoding:
instance_type = "t3.micro"
we can use:
instance_type = var.instance_type
2. Variable Structure
A variable can contain type, default, and description.
variable "instance_type" {
type = string
default = "t3.micro"
description = "EC2 instance type"
}
Here:
variable "instance_type" {
type = string ← Expected data type
default = "t3.micro" ← Default value
description = "..." ← Description of variable
}
If default is not provided:
variable "instance_type" {
type = string
}
Terraform expects the value to come from somewhere else, such as a .tfvars file, CLI argument, or environment variable.
Common Terraform Data Types
The most commonly used Terraform data types are:
string
number
bool
list
map
object
String
Used for text values.
variable "region" {
type = string
default = "ap-south-1"
}
Reference:
var.region
Number
Used for numeric values.
variable "instance_count" {
type = number
default = 2
}
Reference:
var.instance_count
Boolean
Used for true / false configuration.
variable "enable_monitoring" {
type = bool
default = true
}
Reference:
var.enable_monitoring
List
A list stores multiple ordered values of the same type.
variable "availability_zones" {
type = list(string)
default = [
"ap-south-1a",
"ap-south-1b"
]
}
Access values using an index:
var.availability_zones[0]
Here:
var.availability_zones[0]
│ │ │
│ │ └── Index
│ └───────────── Variable name
└──────────────────────── Variable reference
Returns:
ap-south-1a
Map
A map stores values as key-value pairs.
variable "instance_types" {
type = map(string)
default = {
development = "t3.micro"
staging = "t3.small"
production = "t3.medium"
}
}
Access a value:
var.instance_types["production"]
Here:
var.instance_types["production"]
│ │ │
│ │ └── Key
│ └───────────────── Variable name
└─────────────────────────── Variable reference
Returns:
t3.medium
Maps are useful for environment-specific configurations.
Object
An object groups related configuration together.
variable "server" {
type = object({
name = string
instance_type = string
monitoring = bool
})
default = {
name = "backend"
instance_type = "t3.micro"
monitoring = true
}
}
Access individual values:
var.server.name
var.server.instance_type
var.server.monitoring
Think of an object like a structured configuration:
server
│
├── name → backend
├── instance_type → t3.micro
└── monitoring → true
terraform.tfvars
Instead of putting actual values inside variables.tf, we can keep variable declarations and variable values separate.
variables.tf:
variable "region" {
type = string
}
variable "instance_type" {
type = string
}
variable "environment" {
type = string
}
terraform.tfvars:
region = "ap-south-1"
instance_type = "t3.micro"
environment = "development"
Terraform automatically loads:
terraform.tfvars
The flow becomes:
variables.tf
│
│ Defines variables
▼
terraform.tfvars
│
│ Provides values
▼
var.xxx
│
▼
Resources
Example:
resource "aws_instance" "backend" {
ami = "ami-123456"
instance_type = var.instance_type
tags = {
Environment = var.environment
}
}
Variables vs Locals
Variables are inputs from outside the configuration.
variable "environment" {
type = string
}
Reference:
var.environment
Locals are internal reusable values calculated/defined inside Terraform.
locals {
project_name = "taskify"
}
Reference:
local.project_name
Simple difference:
Variable
│
└── Input from outside
terraform.tfvars / CLI / environment
Local
│
└── Internal value used inside Terraform
Example:
variable "environment" {
type = string
}
locals {
app_name = "taskify-${var.environment}"
}
resource "aws_s3_bucket" "uploads" {
bucket = "${local.app_name}-uploads"
}
If:
environment = "production"
then:
var.environment
│
▼
"production"
│
▼
local.app_name
│
▼
"taskify-production"
│
▼
"taskify-production-uploads"
Practical Project Structure
A common small Terraform project can be organized like:
terraform/
│
├── main.tf
├── providers.tf
├── variables.tf
├── outputs.tf
└── terraform.tfvars
Purpose:
providers.tf
│
└── Provider configuration
variables.tf
│
└── Input variable declarations
terraform.tfvars
│
└── Actual variable values
main.tf
│
└── Resources
outputs.tf
│
└── Values Terraform should return
Example flow:
terraform.tfvars
│
▼
variables.tf
│
▼
var.xxx
│
▼
main.tf
│
▼
AWS Resources
│
▼
outputs.tf