Terraform Local Values as Module-Scoped Reusable Expressions

Terraform local values provide a named expression binding mechanism that remains confined to the module in which it is declared. The capability to assign a name to an expression or value creates a single point of definition that can be referenced multiple times across a configuration. Using locals simplifies Terraform configuration because referencing the local multiple times reduces duplication in code. Locals also help write more readable configuration by using meaningful names rather than hard-coding values. Unlike variables found in programming languages, Terraform's locals do not change values during or between Terraform runs such as plan, apply, or destroy. You can use locals to give a name to the result of any Terraform expression, and re-use that name throughout your configuration. Unlike input variables, locals are not set directly by users of your configuration. The tutorial context referenced in the material uses Terraform to deploy a web application on AWS. The supporting infrastructure includes a VPC, load balancer, and EC2 instances. Local values are used to reduce repetition in the configuration, and then combined 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 you can use to manage and execute your Terraform projects.

The scope of locals is a central design constraint that shapes how they are employed. Local values are named, module-scoped values that let you assign an expression once and reuse it throughout your configuration — reducing duplication and making your code easier to read and maintain. If you have ever found yourself repeating the same tag block, name prefix, or computed value across multiple resources, locals are the solution. 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. A Local is only accessible within the local module vs a Terraform variable, which can be scoped globally. This module boundary means that a local value cannot leak out of its defining module and be consumed by a caller, which enforces encapsulation. Local values always stay within their original scope. Terraform distinguishes between its variable types by modular scope. Input variables are external values that can be injected into a module, output values are internal values that can be shared externally, and local values always stay within their original scope.

Definition and Core Purpose

Terraform local values assign a name to an expression or value. Using locals simplifies your Terraform configuration – since you can reference the local multiple times, you reduce duplication in your code. Locals can also help you write more readable configuration by using meaningful names rather than hard-coding values.

The impact of this definition is felt immediately in maintenance workflows. When a hard-coded value is repeated across ten resource blocks and a change is required, the operator must locate and edit ten locations. A local centralizes the definition, so a single edit propagates to every reference. Readability improves because a name such as environment conveys intent more clearly than a raw string development. Reducing duplication also reduces the probability of drift where one instance of a value is updated and another is missed.

In the context of a larger configuration, locals act as internal aliases. 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 you to define temporary values and then reference them 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. If you want to compare Terraform local to a general programming language construct, it will be equivalent to a local temporary variable declared within a function.

Scope and Lifetime Characteristics

Unlike variables found in programming languages, Terraform's locals do not change values during or between Terraform runs such as plan, apply, or destroy. You can use locals to give a name to the result of any Terraform expression, and re-use that name throughout your configuration.

The immutability of locals across runs is important for predictable planning. Because a local does not change between plan and apply, the value computed during plan remains stable through apply and destroy. This stability avoids surprises where an intermediate value shifts because of external input. 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.

Local values 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." Variables enhance code flexibility by allowing for placeholders within blocks of code. Variables can represent different values whenever the code is reused.

Declaration Syntax and Reference Pattern

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 { environment = "development" }

The following code creates a local value called environment and assigns it the string value development.

Locals are declared with the locals block, plural, but referenced with local., singular. This is the most common source of confusion.

locals { bucket_name = "${var.text1}-${var.text2}" }

The reference pattern is:

local.bucket_name

The impact of this naming asymmetry is frequent misreference errors. Operators who assume the same plural form for reference will receive an undefined reference error. Consistent use of local. prefix clarifies intent and distinguishes internal bindings from external inputs.

Multiple locals blocks are permitted. You can also have multiple locals blocks defined in the same configuration or module, Terraform will handle them out for you, but you cannot have multiple local variables with the same name, even though they are in a different locals block. This merging behavior allows logical separation of locals across files while still enforcing a single definition per name.

Data Types and Expression Support

Locals can be assigned any valid Terraform data type, such as a string, list, map, or object.

The ability to hold complex types enables locals to serve as intermediate transformation containers. A local 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.

A local can be used to define default tag values for Terraform resources. This value is used throughout the script.

Practical support includes:

  • Strings for name prefixes and environment identifiers
  • Lists for collections of names or CIDR blocks
  • Maps for tag sets
  • Objects for structured parameter groups

Locals are expressions that define reusable values calculated from input variables or resource attributes.

Relationship to Input Variables and Outputs

Terraform distinguishes between its variable types by modular scope. Input variables are external values that can be injected into a module, output values are internal values that can be shared externally, and local values always stay within their original scope.

AWS CloudFormation uses parameters to represent custom values that can be set and reset from one stack deployment to the next. Similarly, Terraform uses input variables.

variable "thing_i_made_up" { type = string } variable "random_number" { default = 5 } variable "dogs" { type = list(object({ name = string breed = string })) default = [ { name = "Sparky", breed = "poodle" } ] }

To access Sparky’s breed within the configuration, you’d use the variable

var.dogs[0].breed

If a variable has no default and is not classified as nullable, then the value of the variable must be set for each deployment. Otherwise, it’s optional to set a new value for the variable.

The scope difference drives usage decisions. A Local is only accessible within the local module vs a Terraform variable, which can be scoped globally. Another thing to note is that a local in Terraform doesn’t change its value once assigned. A variable value can be manipulated via expressions.

A practical comparison:

Characteristic Local Input Variable Output Value
Scope Module internal Module boundary, injected by caller Module internal, exposed externally
Set by user No Yes No
Changes between runs No, stable across plan apply destroy Yes, per deployment No, derived
Reference syntax local.name var.name output.name

Combining Locals With Variables for Dynamic Values

Locals can be combined with variables to create dynamic default expressions.

Here a variable is declared in the 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" }

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. This is very useful for scenarios where the local needs to be made more dynamic based on input variable values.

The impact is a minimal user input surface. The caller supplies bucket_prefix once, and the local derives bucket_name consistently across all resources. The configuration remains readable because the naming logic is centralized.

Locals are named values that can be assigned and used in your code. They mainly serve the purpose of reducing duplication within the Terraform code. When you use locals in the code, since you are reducing duplication of the same value, you also increase the readability of the code.

Practical AWS Scenarios and Tag Consolidation

The tutorial workflow demonstrates infrastructure with a VPC, load balancer, and EC2 instances. Local values reduce repetition in the configuration, and then combine local values with input variables to require a minimal set of resource tags while still allowing for user customization.

A common pattern is a default tag set local:

locals { default_tags = { Environment = var.environment Owner = var.owner ManagedBy = "terraform" } }

The local is then referenced on multiple resources, ensuring tag consistency without repetition. Changing the tag definition in one place updates all resources.

Locals are ideal for intermediate values derived from other resources, data sources, or expressions. Because locals can’t be overridden from outside the module, they protect internal calculations from external mutation.

Multi-Block Handling and Naming Constraints

You can also have multiple locals blocks defined in the same configuration or module, Terraform will handle them out for you, but you cannot have multiple local variables with the same name, even though they are in a different locals block.

This constraint prevents accidental shadowing. Attempting to define the same local name twice results in a validation error, forcing the author to consolidate or rename.

The merging of multiple blocks is transparent to the user. Locals defined in different files are collected into a single namespace at plan time.

Common Confusions and Error Patterns

Locals are declared with the locals block, plural, but referenced with local., singular. This is the most common source of confusion.

Other frequent errors include attempting to override a local from a module caller, which is not permitted because locals can’t be overridden from outside the module. Another error is assuming locals are re-evaluated between plan and apply; locals do not change values during or between Terraform runs such as plan, apply, or destroy.

When should you use Terraform locals vs. variables?

  • Use a local for an internal computed value, a naming convention, or a tag set that should not be exposed to callers.
  • Use an input variable for a value that the module consumer must provide or may customize.
  • Use an output to expose a value from a module to its caller.

Best practice guidance includes:

  • Provide Descriptions: Add descriptions to variables for better documentation.

Locals are expressions that define reusable values calculated from input variables or resource attributes.

Best Practices and Documentation

Centralize naming conventions in locals to avoid hard-coding. Use meaningful names rather than hard-coding values. Reduce duplication by referencing the local multiple times.

Combine locals with variables for dynamic defaults. This allows a minimal set of resource tags while still allowing for user customization.

Keep locals module-scoped. Do not attempt to use locals as a communication channel between modules; use outputs and inputs for that purpose.

Document locals where they define non-obvious transformations. Although locals are internal, clear names serve as self-documentation.

Conclusion

Terraform local values provide a module-scoped mechanism to name an expression once and reuse it throughout a configuration. They reduce duplication, improve readability, and stabilize values across plan, apply, and destroy. Locals remain internal to the module, cannot be set by users, and do not change between runs. They can be assigned any valid Terraform data type, including string, list, map, or object, and can be combined with input variables to create dynamic yet centralized defaults. The declaration uses a locals block with key-value pairs and is referenced with the singular local. prefix. Multiple locals blocks are allowed, but duplicate names are prohibited. In practice, locals are used for tag sets, name prefixes, and intermediate computed values, especially in AWS scenarios involving VPCs, load balancers, and EC2 instances. The distinction between locals, input variables, and outputs is governed by scope and mutability, with locals providing the internal, immutable binding that supports maintainable, readable Terraform code.

Sources

  1. Terraform locals tutorial
  2. How to manage Terraform locals
  3. AWS Prescriptive Guidance Terraform variables locals outputs
  4. Terraform locals blog
  5. Terraform variables vs locals best practices

Related Posts