DevOps Peach

Linux · Terraform – Infrastructure as Code · Lesson 4 of 5

Variables, outputs, data sources, and modules

Design HCL interfaces and reuse code without hiding dependencies.

Practice interactively →

Input variables

Input variables form a configuration interface; values can come from defaults, tfvars, environment, or CLI according to precedence. Add types and validation to fail early. Do not commit secret tfvars.

variable "instance_type" {
  type    = string
  default = "t3.micro"
}

variable "env" {
  type = string
  validation {
    condition     = contains(["dev", "test", "prod"], var.env)
    error_message = "env must be dev, test, or prod."
  }
}

variable "tags" {
  type    = map(string)
  default = {}
}

Types include string, number, bool, list(...), map(...), and object({...}). terraform.tfvars and any *.auto.tfvars file load automatically; an environment variable such as TF_VAR_env=dev also sets a value. From lowest to highest, precedence runs: default, environment, tfvars files, then -var and -var-file on the command line.

CLI Use case
-var='name=value' Small deliberate override
-var-file=prod.tfvars Environment-specific values
terraform output name Read one output
flowchart LR
  TV["terraform.tfvars<br/>env = dev"] --> V["variables.tf<br/>type, default"]
  V --> M["module vpc<br/>source = ./modules/vpc"]
  DS["data source<br/>latest AMI"] --> R["resource<br/>aws_instance"]
  M --> R
  R --> O["outputs.tf<br/>instance_ip"]
  %% step TV: Values for one environment live in a tfvars file.
  %% step V: Variables declare the inputs with types, defaults and validation.
  %% step M: A module packages resources behind a small interface of inputs and outputs.
  %% step DS: Data sources read existing information, such as the latest AMI ID.
  %% step R: Resources use those values; count and for_each repeat them.
  %% step O: Outputs pass values to people or to other modules.

Data sources, locals, and outputs

data "aws_availability_zones" "available" {}

output "public_ip" {
  value = aws_instance.web.public_ip
}

A data source reads; a resource manages lifecycle. locals name intermediate values so one expression is not repeated. An output is calculated from state after plan or apply and can feed other automation. sensitive = true hides normal display but does not encrypt the value in state.

Repeating resources

count = 3 creates three copies addressed as aws_instance.web[0] and so on. for_each over a map or set creates one copy per key, such as aws_instance.web["api"], which keeps addresses stable when an item is removed from the middle.

Modules

A module packages resources as a reusable unit with inputs and outputs. Every directory of .tf files is a module; the one you run from is the root module.

module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "~> 5.0"
  cidr    = "10.0.0.0/16"
}

Read a module's outputs as module.vpc.vpc_id. Pin the version or ref of an external module, review its source, and run terraform init after adding or changing a source. The public Terraform Registry lists community and official modules.

The built-in templatefile() function replaces the old template provider for local template files.

Practice interactively →