
If your Terraform configuration is full of repeated expressions, hard-to-read resource arguments, or values you keep copying from one block to another — locals are the fix.
Terraform locals let you define a value once, give it a clear name, and reuse it anywhere in your configuration. They are one of the simplest features in Terraform, but also one of the most impactful for keeping your codebase clean, consistent, and easy to maintain.
This guide explains what locals are, when to use them, how they compare to variables and outputs, and how to use them effectively — with real examples throughout.
What Are Terraform Locals?
A local value in Terraform is a named expression you define inside a locals block. Once defined, you reference it using local.<name> anywhere in the same module.
Here is the simplest possible example:
That is it. You define the value once in the locals block, and reference it with local.environment wherever you need it.
Of course, locals become much more powerful when you use them to compute values rather than just store static strings:
Locals are evaluated lazily — Terraform only computes a local value when it is actually referenced. You can define as many as you like without any performance cost.
Locals vs Variables: What Is the Difference?
This is one of the most common points of confusion for teams new to Terraform. Both locals and variables let you name a value and reuse it — but they serve very different purposes.
The simple rule is: use variables for values that should come from outside the module, and use locals for values you compute or derive inside the module.
A Common Mistake: Using Variables Where Locals Belong
Teams sometimes reach for a variable when they actually need a local. Here is an example of the problem and the fix:
Using a local here keeps the module interface clean. Callers only need to supply app_name and environment — the derived values are handled internally.
Locals vs Outputs: When to Use Each
Locals and outputs can look similar at first glance — both give names to values. But they have completely different audiences.
Terraform Locals Examples
Here are the most practical and commonly used patterns for locals in real Terraform configurations.
Example 1 — Consistent Resource Naming
One of the most valuable uses of locals is building a naming convention once and applying it everywhere. This eliminates typos, inconsistencies, and hard-to-find bugs caused by mismatched names across resources.
Example 2 — Centralised Tagging
Most organisations require a standard set of tags on every cloud resource for cost attribution, compliance, and governance. Locals make this effortless:
Example 3 — Simplifying Complex Expressions
Sometimes a resource argument involves a long, nested expression that is hard to read inline. A local gives it a name and makes the resource block much cleaner:
Example 4 — Conditional Logic
Locals work well for computing conditional values that would be cluttered if written directly in a resource argument:
Using Locals in Terraform Modules
Locals are especially valuable inside reusable modules. They let you encapsulate derived logic so that callers only need to supply a small set of clean inputs — the module handles the rest internally.
Pattern: Deriving All Internal Names From a Single Input
A well-designed module typically takes a few key inputs and uses locals to derive everything else:
The caller of this module only needs to pass name and environment. Every other naming decision is handled internally by locals. This is the essence of good module design.
Pattern: Locals That Reference Data Sources
Locals can reference data sources as well as variables, which lets you build derived values from live cloud data:
Locals and Governance: How env zero Helps
Locals are a module-level tool — they keep individual configurations clean. But in large teams, the real challenge is making sure every team is using the same naming conventions, the same tagging standards, and the same structural patterns across hundreds of modules and environments.
That is the governance problem env zero is built to solve.
• Standardised module library — env zero provides approved, pre-built modules where the locals, naming conventions, and tag maps are already defined correctly. Teams consume them rather than reinventing them.
• Policy enforcement — automated checks validate that required tags exist, naming conventions are followed, and sensitive values are not being misused — all before a terraform apply is allowed to run.
• Drift detection — if a resource is renamed or retagged manually outside of Terraform, env zero flags the drift immediately. Your locals-driven naming strategy stays the source of truth.
• Cost attribution — when common_tags locals include the right cost centre and team labels, env zero uses that data to give you accurate, real-time cost breakdowns per team, project, and environment — without any extra configuration.
Clean locals make individual modules better. env zero makes the whole platform consistent.
Summary
Terraform locals are one of the most practical tools for writing clean, maintainable infrastructure code. They let you:
• Define a value once and reuse it everywhere in a module — no more copy-paste
• Compute derived values using functions, conditionals, and references to other resources
• Simplify complex expressions by giving them meaningful names
• Centralise naming and tagging conventions so the whole module stays consistent
• Keep module interfaces clean by handling internal logic privately, away from variables
The more complex your Terraform codebase grows, the more value locals deliver. Start using them early, name them clearly, and group them logically — and your configuration will be significantly easier for your whole team to read, review, and maintain.
Locals also pair naturally with other Terraform constructs. A common pattern is feeding a local list or map into a dynamic block to generate repeated nested blocks, or referencing one inside a for_each expression to create multiple resource instances from a single configuration.
Frequently Asked Questions
Can I use locals across multiple Terraform files?
Yes. Terraform merges all .tf files in a directory into a single configuration, so a local defined in locals.tf is accessible in main.tf, outputs.tf, and every other file in the same module. The convention is to keep locals in a dedicated locals.tf file for clarity.
Can locals reference resource attributes?
Yes — with one important caveat. A local can reference a resource attribute, but that attribute must be known at plan time for the local to be usable in expressions that also need to be known at plan time (like count or for_each). If the value is only known after apply, Terraform will raise an error if you try to use it where a static value is required.
What is the difference between a local and a variable default?
A variable default is a fallback value for an external input — it can be overridden by a caller. A local is always determined by the module itself and cannot be overridden externally. If you want a computed value that callers cannot change, use a local. If you want a sensible fallback that callers can override, use a variable with a default.
Are locals re-evaluated on every terraform plan?
Locals are expressions, not persistent values — they are evaluated fresh each time Terraform runs a plan or apply. If a local depends on timestamp() for example, its value will change between runs. If you want a stable value that does not change, use plantimestamp() instead, or compute the value once and store it in a resource or data source.
Can I use locals to conditionally include resources?
Indirectly, yes. You can use a local to compute a boolean condition, then use that local in a count or for_each expression to conditionally create a resource:
.webp)