Variables make one configuration reusable across environments; outputs pass values to people and other code.
An input variable declares a parameter:
type:string,number,bool,list(string),map(number),object({ name = string, size = optional(number, 10) })...default: makes it optional.description: shows up in docs and prompts.sensitive = true: hides the value in plan output.nullable = false: rejectsnull.
Use it as var.name. Values come from, lowest to highest precedence: defaults, environment variables TF_VAR_name, terraform.tfvars, *.auto.tfvars files, then -var-file and -var on the command line. Variables without a value make Terraform prompt interactively, which you never want in automation.
A common pattern is one .tfvars file per environment: terraform plan -var-file=prod.tfvars.
An output exposes a value after apply: output "vpc_id" { value = aws_vpc.main.id }. Outputs are printed after apply, read with terraform output (-raw name for scripts, -json for everything), and are how child modules return values to their parent.
Mark outputs that contain secrets sensitive = true. They are hidden from the console, but still stored in plain text in the state.
Example
variable "environment" {
type = string
description = "Deployment environment"
}
variable "instance" {
type = object({
type = string
count = optional(number, 1)
})
default = { type = "t3.small" }
}
output "summary" {
value = "${var.environment}: ${var.instance.count} x ${var.instance.type}"
}
# prod.tfvars: environment = "prod"
# instance = { type = "m7i.large", count = 3 }
# terraform apply -var-file=prod.tfvars
# summary = "prod: 3 x m7i.large"
# TF_VAR_environment=dev terraform plan # env var formRemember
- Typed variables with defaults, optional() attributes and descriptions
- Precedence: default < TF_VAR_ < tfvars < auto.tfvars < -var-file/-var
- Outputs return values; sensitive hides display, not storage
Watch out for
- Leaving required variables unset in CI, so terraform waits for interactive input.