Outputs and Locals
Outputs and locals solve two different but complementary problems. Output values are how a module communicates data outward — a child module exposes an output so its caller (the root module or a parent module) can use that value, and a root module's outputs are what terraform output prints to the CLI or what remote state data sources read from a different configuration. Local values, in contrast, are purely internal: they let you assign a name to an expression so it can be reused within the same module without repeating logic, improving readability and reducing duplication.
Cricket analogy: A junior academy's scouting report is an output — it hands a promising batsman's stats outward to the national selectors — while a coach's private shorthand notes on 'form rating' used only within that academy's own meetings are purely internal, like a local value.
Declaring Outputs
An output block takes one label (its name) and typically a value argument holding an expression. Outputs can also carry a description, a sensitive flag to redact the value from CLI output (though, like sensitive variables, this does not encrypt it in state), and a depends_on argument for the rare cases where Terraform can't infer the dependency automatically.
Cricket analogy: A player-of-the-match announcement carries one label and a value — the chosen name — plus an optional note explaining the choice, and a broadcaster can mark an injury detail as 'sensitive' to withhold from the live feed until confirmed, without hiding it from the medical team.
output "vpc_id" {
description = "ID of the created VPC"
value = aws_vpc.main.id
}
output "db_password" {
description = "Generated database password"
value = random_password.db.result
sensitive = true
}
locals {
name_prefix = "${var.project}-${var.environment}"
common_tags = {
Project = var.project
Environment = var.environment
ManagedBy = "terraform"
}
}
resource "aws_s3_bucket" "data" {
bucket = "${local.name_prefix}-data"
tags = local.common_tags
}Locals: Naming Computed Values
A locals block can define any number of named values in one place, and each local can reference variables, resource attributes, or even other locals declared earlier. This is especially useful for values that are computed once and reused several times — like a naming prefix, a merged tags map, or a conditional expression — because it avoids repeating the same expression (and risking inconsistency) across multiple resource blocks. Unlike variables, locals cannot be set by the caller; they are computed entirely within the module.
Cricket analogy: A team's analyst maintains a single sheet of named values — average partnership runs, a merged fielding-position map, a form-adjusted rating — computed once and reused across every pre-match briefing instead of recalculating from raw scores each time, unlike player stats the board itself supplies.
A useful mental model: variables are a module's inputs, outputs are a module's outputs, and locals are a module's private scratch space — internal working values that never cross the module boundary in either direction.
Overusing locals for values that are only ever used once can make configuration harder to read by adding an unnecessary layer of indirection. Reach for a local when a value is reused multiple times or when naming it clarifies intent — not reflexively for every expression.
When you call a child module, its outputs become accessible in the parent as module.<name>.<output>. This is the primary mechanism for passing data between modules — for example, a networking module might output subnet IDs that a compute module then consumes as an input variable. At the root level, outputs are also what a terraform_remote_state data source reads when one Terraform configuration needs to consume values produced by a separate, independently-applied configuration.
Cricket analogy: A fielding coach's drill outputs a player's reaction-time score, which the head coach then consumes as an input when picking the slip cordon — the same way a networking module's subnet ID output feeds directly into a compute module's input variable.
- Output blocks expose values outward: from a child module to its caller, or from a root module to the CLI/remote state readers.
- Local values name an expression for internal reuse within the same module; they are not settable by callers.
- Child module outputs are accessed in the parent as module.<name>.<output>.
- sensitive = true on an output redacts CLI display but does not encrypt the value in state.
- Locals can reference variables, resource attributes, and other locals declared earlier.
- Overusing locals for single-use values adds unnecessary indirection; use them when a value is reused or naming aids clarity.
Practice what you learned
1. What is the primary purpose of an output value in a child module?
2. How do you access an output named 'vpc_id' from a child module called 'network' in the parent configuration?
3. What is a key difference between a local value and an output value?
4. Does marking an output as sensitive = true encrypt its value in the state file?
5. Which of the following is a reasonable use case for a local value?
Was this page helpful?
You May Also Like
Variables and Variable Types
Input variables let Terraform configurations be parameterized and reused across environments. This topic covers declaring variables, type constraints, defaults, validation, and how to supply values.
Expressions and Functions
HCL expressions let you reference values, perform operations, and transform data using Terraform's extensive built-in function library. This topic covers references, operators, conditionals, and common functions.
Terraform Modules Explained
Modules are Terraform's mechanism for packaging and reusing configuration. This topic explains what a module is, root vs. child modules, and how module calls connect inputs, resources, and outputs.
Writing a Reusable Module
Turning ad-hoc configuration into a well-designed reusable module requires thoughtful input/output design, sensible defaults, and internal structure. This topic walks through the practical craft of module authoring.
Related Reading
Related Study Notes in DevOps
Browse all study notesNginx Study Notes
DevOps · 30 topics
DevOpsAnsible Study Notes
DevOps · 30 topics
DevOpsAdvanced Kubernetes Study Notes
Kubernetes · 30 topics
DevOpsAdvanced Bash Scripting Study Notes
Bash · 30 topics
DevOpsApache Kafka Study Notes
Kafka · 30 topics
DevOpsDocker & Kubernetes Study Notes
YAML · 40 topics