Variables, outputs, and modules¶
Play it
Drift Detective: Keep config, state and reality in agreement through drift, imports and locks.
The game links back to this page from: Refactoring into a module.
Variables¶
variable "greeting" {
description = "Text written to the generated file."
type = string
default = "hello from the cookbook"
}
Set a value, in order of precedence (later overrides earlier):
terraform apply -var 'greeting=hi' # CLI flag
terraform apply -var-file="prod.tfvars" # -var-file
# TF_VAR_greeting=hi terraform apply # environment variable
# a *.auto.tfvars file in the working dir is loaded automatically
Use sensitive = true on a variable holding a secret so Terraform redacts it from plan
output — it's still stored in plaintext in state, so pair it with a remote backend that
encrypts state at rest.
Outputs¶
terraform output # all outputs
terraform output path # one output, unquoted with -raw
terraform output -json # machine-readable, for piping into another tool/module
Modules¶
A module is just a directory of .tf files; every root config is itself a module.
Extract one once an example grows past a single reusable unit:
terraform get # (re)download/refresh module sources
terraform init -upgrade # also upgrade provider versions per version constraints
Conventions worth following as a config grows:
- One resource concern per file (
main.tf,variables.tf,outputs.tf) — seeCONTRIBUTING.md's guidance for this repo's examples. - Pin
required_versionand every provider's version in aterraform {}block (seeexamples/local-file/main.tf) soterraform initis reproducible. - A module's
variables.tfis its public interface — keep it minimal and documented (descriptionon every variable and output).
Refactoring into a module¶
Moving a resource into a module changes its address (aws_instance.web_a becomes
module.svc_a.aws_instance.web). Terraform tracks resources by address, so a plain plan proposes
to destroy the old object and create the new one: for a database or bucket, that is data loss. Tell
Terraform the object moved instead:
terraform plan # "has moved to": no destroy, no create
terraform state mv aws_instance.web_a module.svc_a.aws_instance.web # one-off alternative, edits state now
Prefer moved blocks: they are reviewed in the pull request and work for everyone who applies the
config. state mv changes only your state. Either way, read the plan: a wrong pair still shows
changes.