Learning bite
Variables and outputs
Create a typed interface and understand what values are persisted.
On this page
Give the caller a small interface
Editing a literal for every environment makes a configuration difficult to reuse and review. An input variable allows a caller to supply a value. A local value gives an internal expression a readable name. An output exposes a result. None of these is a shell variable or a line-by-line assignment.
Continue in terraform-basics. Replace input = "local-foundations" in terraform_data.name with input = var.environment. Keep the dependent label resource. Add these blocks to main.tf:
variable "environment" {
description = "Name for this local practice environment"
type = string
default = "dev"
validation {
condition = contains(["dev", "qa"], var.environment)
error_message = "Choose dev or qa for this local fixture."
}
}
locals {
purpose = "capacity-study"
}
output "study_label" {
value = terraform_data.label.output
}
output "summary" {
value = "${local.purpose}: ${var.environment}"
}
The variable's type rejects values that cannot satisfy it; validation narrows allowed values further. A local is referenced with local.purpose, while an input uses var.environment. You can organize these blocks into variables.tf and outputs.tf later; Terraform still treats the directory as one module.
Run terraform fmt, terraform validate, and terraform plan -var='environment=qa'. Expect the name input to become qa and the dependent label eventually to become study-qa. Run the plan with environment=production and read the validation failure. Do not apply either plan yet.
See which input wins
Create practice.tfvars containing:
environment = "dev"
Compare terraform plan -var-file=practice.tfvars with terraform plan -var-file=practice.tfvars -var='environment=qa'. The latter explicit argument wins because command-line assignments are processed in order. practice.tfvars is not auto-loaded; you selected it explicitly.
For local CLI root inputs, the increasing-precedence order is defaults, TF_VAR_... environment variables, terraform.tfvars, terraform.tfvars.json, *.auto.tfvars/JSON in lexical order, then explicit command-line assignments. Remote workspace settings have their own documented context. Avoid scattering a simple exercise across all these sources; use one normal location and an intentional override.
Types and iteration are design choices
A list preserves positions, a map uses keys, and an object describes named attributes with types. In terraform console, try upper("dev"), contains(["dev", "qa"], "prod"), and {dev = 1, qa = 2}["qa"]. Expected values are "DEV", false, and 2. Exit the console with exit.
When creating many resources, count identifies instances by numeric index, while for_each identifies them by stable keys. Removing an early item from an indexed list can change which object belongs at later addresses. This is why collection choice can affect replacement, not just syntax. Practice address migrations later rather than changing a managed collection blindly.
What an output does and does not mean
terraform output reads applied state; editing a file does not update that output immediately. Marking a value sensitive hides it in ordinary display, but normally does not remove it from state or saved plans. Ephemeral and write-only features have specific supported contexts; they are not a substitute for protecting all state.
Checkpoint: a qa plan followed by terraform output can still show an older value because you have not applied the plan. A validation error for production is a rejected input, not a cloud outage. Next, inspect how Terraform remembers accepted changes.
References: input variables↗, locals↗, outputs↗, and sensitive data↗.
Your notes and evidence
Record observations, questions, or links to your work. Keep credentials out of your notes.
Back up or restore this path
Progress and notes stay in this browser. A backup contains only this learning path.