Terraform local values provide a mechanism to assign a name to an expression or value inside a module and then reuse that name throughout the configuration. The construct exists to reduce duplication and to replace hard-coded values with meaningful identifiers that can be referenced multiple times. By naming an expression once, the configuration becomes easier to read and maintain, because a change to the named expression propagates to every place it is referenced. The use of locals does not alter the declarative nature of Terraform, because locals do not change values during or between Terraform runs such as plan, apply, or destroy. Locals give a name to the result of any Terraform expression and allow that name to be reused across resources, data sources, and other expressions within the same module.
The practical impact for teams is visible in large infrastructure codebases where the same tag block, name prefix, or computed value would otherwise be copied across dozens of resources. Repeating the same literal creates a maintenance burden, because an update requires finding and editing every occurrence. With a local, the single definition becomes the source of truth. When the local is referenced with the singular prefix local.<name>, the configuration expresses intent rather than implementation detail. Unlike input variables, locals are not set directly by users of the configuration. They are internal to the module and cannot be overridden from outside, which makes them suitable for intermediate values derived from other resources, data sources, or expressions.
A tutorial context that illustrates this is the deployment of a web application on AWS with supporting infrastructure including a VPC, load balancer, and EC2 instances. The tutorial first builds the infrastructure and then uses local values to reduce repetition in the configuration, and then combines local values with input variables to require a minimal set of resource tags while still allowing for user customization. The same workflow can be completed using Terraform Community Edition or HCP Terraform. HCP Terraform is a platform that can be used to manage and execute Terraform projects.
What Terraform Locals Are and Why They Exist
Terraform locals are named values that can be assigned and used in code. They mainly serve the purpose of reducing duplication within the Terraform code. When locals are used in the code, since duplication of the same value is reduced, readability also increases. In a general programming language comparison, a Terraform local is equivalent to a local temporary variable declared within a function. The construct allows temporary values to be defined and referenced elsewhere in the configuration.
All programming languages have a way to express and store values within the context of a code block. In the case of Terraform configurations, that functionality is delivered through Terraform local values. These allow temporary values to be defined and then referenced elsewhere in the configuration. Local values, often called locals or Terraform local variables, can be used to store an expression that will be referenced multiple times, perform data transformation from other sources, or store static values to be used in the configuration.
Locals are one of three varieties of Terraform variables that can be used to request or public values, with the other two being input variables and output values. Locals are expressions that define reusable values calculated from input variables or resource attributes. Thinking about the complete Terraform configuration as a single function helps place locals in context. As far as variables are concerned, they are used with the function in the form of arguments, return values, and local variables. These are analogous to input variables, output variables, and local variables in Terraform.
Declaration Mechanics and Syntax Rules
Defining local values in Terraform code is done using a locals block, with each local assigned a name and value in the format of a key-value pair. Locals can be assigned any valid Terraform data type, such as a string, a list, a map, or an object. The locals block is plural, but references are singular with the prefix local.<name>. This is the most common source of confusion.
You can also have multiple locals blocks defined in the same configuration or module. Terraform will handle them, but you cannot have multiple local variables with the same name, even though they are in a different locals block.
A minimal declaration example creates a local value called environment and assigns it the string value development:
locals {
environment = "development"
}
A more dynamic example combines a variable with a literal:
locals {
bucket_name = "${var.text1}-${var.text2}"
}
When a local is used, the expression is evaluated once and the result is reused. Because the value does not change during or between runs such as plan, apply, or destroy, the behavior is stable across the lifecycle of the configuration.
Scope, Accessibility, and Module Boundaries
Terraform locals are named, module-scoped values that let you assign an expression once and reuse it throughout your configuration, reducing duplication and making code easier to read and maintain. The scope is limited to the module in which the locals block is defined. A local is only accessible within the local module, whereas a Terraform variable can be scoped globally and passed between modules.
Unlike input variables, locals can't be overridden from outside the module, which makes them ideal for intermediate values derived from other resources, data sources, or expressions. The inability to override from outside is a deliberate design choice that protects internal calculations from external manipulation.
If you have ever found yourself repeating the same tag block, name prefix, or computed value across multiple resources, locals are the solution. The module boundary ensures that a local defined in one module does not leak into another unless explicitly exported via outputs.
Locals Versus Input Variables and Output Values
The differences between locals, input variables, and output values shape how a configuration is structured.
| Aspect | Terraform Local | Terraform Input Variable | Terraform Output Value |
| Scope | Module-scoped, internal | Can be scoped globally, passed into module | Exposed out of module |
| Set by user | No, not set directly by users | Yes, set by users via tfvars, CLI, environment | No, computed |
| Mutability | Does not change value once assigned | Value can be manipulated via expressions and overrides | Computed after apply |
| Reference syntax | local.<name> | var.<name> | module.<name>.<output> |
| Purpose | Reduce duplication, name expressions | Accept external configuration | Publish results |
A local in Terraform doesn't change its value once assigned. A variable value can be manipulated via expressions. This makes it easier to assign expression outputs to locals and use them throughout the code instead of using the expression itself at multiple places.
Locals are declared with the locals block plural but referenced with local.<name> singular. This naming asymmetry is a frequent source of errors for new users.
Combining Locals With Variables for Dynamic Defaults
Locals can be easily combined with Terraform variables to create complicated default value expressions for the Terraform local. This is very useful for scenarios where the local needs to be made more dynamic based on input variable values.
A variable can be declared in a variables.tf file in a Terraform module:
variable "bucket_prefix" {
type = string
default = "mybucketname"
}
This variable can be used as a default value to the local in the Terraform script:
locals {
bucket_name = "${var.bucket_prefix}-bucket1"
}
The resource then references the local:
resource "aws_s3_bucket" "my_test_bucket" {
bucket = local.bucket_name
acl = "private"
}
As you can see, a local can be easily combined with a Terraform variable to create complicated default value expressions for the Terraform local. The variable provides external customization, while the local encapsulates the derived naming logic. The combination allows a minimal set of inputs from the user while still enforcing consistent naming conventions internally.
Multiple Locals Blocks and Naming Restrictions
You can also have multiple locals blocks defined in the same configuration or module. Terraform will handle them. The restriction is that you cannot have multiple local variables with the same name, even though they are in a different locals block. Duplicate names cause a conflict and will fail validation.
Having multiple blocks can improve readability by grouping related locals together, for example one block for naming conventions and another block for tags. The order of declaration does not affect evaluation, because Terraform builds a dependency graph before evaluation.
Data Types and Expression Support
Locals can be assigned any valid Terraform data type, such as a string, list, map, or object. They can store an expression that will be referenced multiple times, perform data transformation from other sources, or store static values to be used in the configuration.
The guide material mentions using locals with strings, lists, maps, for loops, and conditional expressions. While specific loop and conditional examples are not provided in the reference facts, the ability to assign any valid Terraform expression to a local implies support for those constructs.
Because locals are expressions, they can reference other locals, variables, resource attributes, and data source outputs. The result is evaluated at plan time and remains stable for the duration of the run.
Practical AWS Patterns and Tutorial Context
The tutorial that uses locals to deploy a web application on AWS includes a VPC, load balancer, and EC2 instances. Local values are used to reduce repetition in the configuration and to combine with input variables to require a minimal set of resource tags while still allowing user customization.
A common pattern is to declare a local to define default tag values for Terraform resources. This value is used throughout the script. By centralizing tags in a local, updates to organizational tagging requirements require a single edit rather than edits across many resource blocks.
Another pattern is to use a local for name prefixes. A local that combines a variable prefix with a resource-specific suffix ensures consistent naming across S3 buckets, EC2 instances, and load balancers without repeating the concatenation logic.
The impact for operators is reduced drift and fewer errors when renaming resources or changing tagging policies. The configuration expresses the intent once, and Terraform propagates the change consistently.
Common Errors and Confusion Points
The most common source of confusion is the declaration versus reference naming. Locals are declared with the locals block plural but referenced with local.<name> singular. Attempting to reference a local as locals.<name> will fail.
Another error is attempting to override a local from outside the module. Because locals cannot be overridden from outside the module, attempts to pass a value via module inputs will not affect the local. The correct approach is to make the local depend on an input variable.
Duplicate local names across multiple blocks are prohibited. Terraform will report a conflict if the same name appears in two blocks.
Understanding that locals do not change values during or between runs is important. A local is evaluated once per run based on the inputs available at that time. It cannot be used to create mutable state within Terraform.
Implementation Workflow and Best Practices
Provide descriptions to variables for better documentation. While this guidance is specific to variables, the same principle applies to locals: meaningful names improve readability.
When planning a module, identify repeated literals, repeated tag blocks, repeated name constructions, and repeated computed values. Promote those to locals. Keep locals focused on internal derivation rather than external configuration. Use input variables for values that users should control, and use locals to derive stable internal values from those inputs.
Combining locals with variables creates a separation of concerns. The variable defines the user-facing knob, and the local defines the internal naming or transformation logic. This allows a minimal set of resource tags to be required from the user while still allowing customization.
Because Terraform configuration can be thought of as a single function, locals act as local variables inside that function, input variables act as arguments, and outputs act as return values. Maintaining that mental model helps keep the module interface clean.
Note about tooling evolution: New versions of Terraform are placed under the BUSL license, but everything created before version 1.5.x stays open-source. OpenTofu is an open-source version of Terraform that will expand on Terraform's existing concepts and offerings. The concepts of locals remain consistent across implementations.
Conclusion
Terraform locals provide a module-scoped mechanism to name expressions and reuse them, which reduces duplication and improves readability across configurations. The construct is distinct from input variables because locals are not set directly by users, cannot be overridden from outside the module, and remain stable during plan, apply, and destroy operations. Declaration uses a plural locals block with key-value pairs, while references use the singular local.<name> prefix. Locals can be assigned any valid Terraform data type and can combine with input variables to create dynamic yet internally consistent values.
The practical value emerges in scenarios with repeated tag blocks, name prefixes, and computed values across AWS resources such as VPCs, load balancers, EC2 instances, and S3 buckets. By centralizing those values in locals, teams reduce maintenance burden and lower the risk of inconsistency. Multiple locals blocks are permitted, but duplicate names are prohibited. The scope is confined to the module, which protects internal derivations from external manipulation.
Understanding the relationship between locals, input variables, and output values clarifies how to structure modules: variables accept external configuration, locals derive internal values, and outputs publish results. Proper use of locals leads to configurations that are easier to read, easier to maintain, and less prone to error when requirements change.