Local Values
A local value names an expression so you compute it once and reuse it — a common tag map, a constructed name prefix, a derived list. Where variables are inputs from outside, locals are internal intermediate values. Used well they remove repetition and name intent; over-used they add a layer of indirection that makes a config harder to read, not easier.
The single most common good use is tagging. Every resource in an AWS account should carry a consistent set of tags, and copying that map onto 40 resources is both noisy and a guarantee that one of them drifts. A common_tags local computed once and merged everywhere fixes that, and it is the pattern you will reach for in nearly every configuration.
Declaring Locals
A locals block holds one or more named assignments, referenced as local.name. The values can be literals or any expression, and a local may reference other locals, variables, resources, and data sources. The block below builds a name prefix from two variables and a tag map that reuses it.
locals { name_prefix = "${var.project}-${var.environment}" common_tags = { Project = var.project Environment = var.environment ManagedBy = "terraform" } }
The common_tags Pattern
You apply the shared tags by merging the local into each resource's own tags with the merge function, so every resource gets the base set plus anything specific to it. Change a tag in one place — the local — and it propagates to every resource on the next apply, instead of being edited 40 times by hand.
resource "aws_instance" "app" { ami = "ami-0abc123" instance_type = "t3.micro" tags = merge(local.common_tags, { Name = "${local.name_prefix}-app" Role = "web" }) }
DRY Without Over-Abstraction
A local earns its place when an expression repeats or when naming it clarifies intent. The opposite — wrapping a single literal that appears once behind a local — adds an indirection that makes a reader jump to the definition to learn what is otherwise sitting right there. The test is whether the name explains more than the expression it replaces; if it doesn't, inline it.
Locals Compared to Variables
The dividing line is direction. A variable is set from outside and a caller controls it, but it cannot reference resources or data sources. A local is computed inside the config, cannot be set from outside, and can reference anything — variables, resources, data sources, and other locals. Use a variable for what comes in, a local for what you derive from it.
Keeping Locals Shallow
Locals can reference other locals, which is useful for one or two steps and a trap past that. A chain where understanding local.a means reading local.b, which means reading local.c, has turned a derivation into a puzzle. Keep the dependency depth shallow; if a local needs three other locals to make sense, the abstraction is hiding the data flow rather than clarifying it.
Input variable — an external input the caller sets, with a type and optional default. It cannot reference resources or data sources. Use it for anything that comes in from outside: a region, an environment name, an instance count.
Local value — an internal computed value the caller can't set, which can reference variables, resources, data sources, and other locals. Use it for anything you derive inside the config: a name prefix, a merged tag map, a list reshaped from inputs.
- Turning every literal into a local, adding indirection that makes a reader chase a definition for a value that appears exactly once.
- Trying to override a local from outside the module — you can't; an external input is what a variable is for.
- Building a deep chain of locals referencing locals until following the data flow means reading five definitions to understand one.
- Duplicating the same tag map across dozens of resources instead of a single
common_tagslocal, so one resource silently drifts. - Putting a value a caller should control into a local, forcing an edit to the module's code instead of passing a different input.
- Define a
common_tagslocal andmergeit into every resource for consistent, single-source tagging. - Introduce a local when an expression repeats or when a name clarifies intent, not reflexively for every value.
- Keep locals shallow and readable; if a local needs three other locals to understand, reconsider the abstraction.
- Reach for a variable for an external input and a local for an internal derivation — don't blur the two roles.
- Build a
name_prefixlocal once and reuse it for resource names so naming stays consistent across the stack.
Knowledge Check
What is the core difference between a local value and an input variable?
- A variable is set from outside and can't reference resources; a local is computed inside and references anything
- A local is set from outside the module by the caller; a variable is the one computed internally from expressions
- They are fully interchangeable — the two keywords are simply aliases for the same construct
- A variable can reference resource attributes directly but a local cannot
Which is a genuinely good use of a local?
- A
common_tagsmap merged into every resource so a tag change happens in one place - Wrapping a single string literal that appears only once, purely to give it a friendly name
- Exposing a value that a caller of the module needs to set differently per environment
- Storing a secret in a local so it never appears in the state file
Why can't you set a local value from outside the module?
- Locals are internal derivations by design; external inputs are exactly what variables are for
- Locals are read-only constants that Terraform freezes and computes just once at provider install time
- You actually can, by passing the
-local=name=valueflag on the command line - Locals are encrypted at rest, so external code has no way to write to them
What is the downside of a deep chain of locals each referencing the previous one?
- Understanding one value means reading several definitions, hiding the data flow rather than clarifying it
- Terraform flatly refuses to evaluate any local that references another local declared in the same locals block
- It forces every resource that depends on the chain to be recreated on each apply
- A deeply chained local can no longer be referenced from a resource's tags
You got correct