Variables, outputs & locals
Parameterize and expose values.
Hard-coded values make a config rigid and un-reusable. Terraform has three tools to fix that: input variables (values you pass in), outputs (values you expose out), and locals (named expressions computed inside). Together they turn a one-off script into a parameterized, composable configuration — the same code deploying dev and prod by changing inputs, and feeding values to other configs through outputs.
variable "instance_type" {type = stringdefault = "t3.micro"description = "EC2 size for the web tier"}variable "environment" {type = stringvalidation { # reject bad input earlycondition = contains(["dev", "staging", "prod"], var.environment)error_message = "environment must be dev, staging, or prod."}}
Passing variables in
You reference a variable as var.name, and supply its value one of several ways, in a defined precedence: a default in the block, a terraform.tfvars file, -var on the command line, or a TF_VAR_name environment variable (highest-priority, and the clean way to inject secrets in CI). Precedence means an environment variable or -var overrides a tfvars file, which overrides the default — so the same code adapts per environment without edits.
# a prod.tfvars file, or CLI, or env var — same variable, different value$ terraform apply -var-file=prod.tfvars$ terraform apply -var="instance_type=t3.large"$ TF_VAR_instance_type=t3.large terraform apply # env var (good for secrets/CI)
Outputs and locals
Outputs expose values after apply — an instance’s IP, a database endpoint — printed at the end and, importantly, readable by other configurations through remote state, which is how modules and stacks pass data to each other. Locals name a computed expression so you write it once and reuse it (a naming convention, a merged tag set). Mark sensitive outputs so Terraform redacts them from CLI output.
locals {name_prefix = "${var.environment}-web" # computed once, reused}resource "aws_instance" "web" {instance_type = var.instance_typetags = { Name = local.name_prefix }}output "public_ip" {value = aws_instance.web.public_ip}output "db_password" {value = aws_db_instance.main.passwordsensitive = true # redacted from CLI output}