Infrastructure as Craft: Variables vs Locals

2 min read
Mar 11, 2026 9:21:37 AM

As DevOps engineers, we often talk about “infrastructure as code,” but too rarely do we talk about code as a craft. Terraform is not merely a tool for provisioning resources; it is a language with semantics, constraints, and design intent. Ignoring those distinctions leads to configurations that technically work, yet are brittle, opaque, and hostile to long-term maintenance. As the first in a short series about code as craft with Terraform, I’d like to talk about one of the most common examples of this: the habit of (over)using Terraform locals where plain input variables would be clearer and more honest.

At first glance, Terraform locals appear attractive. They reduce repetition, allow light computation, and can make a file look tidy. Used sparingly and intentionally, they are valuable. Used to wrap or re-express simple variables, however, they add indirection without meaning—and that is where problems begin.

The first issue is interface erosion. Variables define the public interface of a module. They declare, explicitly and upfront, what a module expects from its caller. This is not accidental; it is how Terraform enforces contracts between layers of infrastructure. When a module defines a variable and then immediately aliases it through a local—local.region = var.region, for example—the interface becomes blurred. Readers are forced to ask which name matters, and why both exist. Over time, engineers stop trusting variables.tf as the authoritative source of truth, which defeats its purpose entirely.

Second, this pattern harms readability through unnecessary indirection. Locals are meant to express derived values or shared computations. When they are used merely to restate simple variables, they add a cognitive hop with no semantic gain. Every additional name is something the reader must hold in working memory. In isolation this feels harmless; at scale it becomes exhausting. A codebase full of trivial locals is not “clean,” it is verbose in the wrong places. Craftsmanship favors directness: if a value comes from a variable, use the variable.

Third, excessive aliasing obscures change impact. Terraform surfaces variable changes clearly at module boundaries. When variables are passed directly into resources, the relationship between input and effect is obvious in both code review and plan output. Introducing locals purely as pass-throughs dilutes that clarity without any payback or benefit. A reviewer must trace values across multiple files or locations to confirm that nothing meaningful is happening in between. This slows reviews and increases the chance that real changes are missed among structural noise.

Fourth, this habit encourages future misuse. Once locals exist as a general abstraction layer, they tend to accumulate logic opportunistically. A simple alias becomes a conditional, then a string manipulation, then a behavioral switch tied to naming conventions. What began as “just a local for consistency” quietly turns into hidden policy. The module’s behavior changes without any corresponding change to its declared inputs. This is how configuration becomes surprising, and surprise is the enemy of operational reliability.

Finally, there is the matter of intent. Variables answer the question, “What is configurable?” Locals answer the question, “What is derived?” When locals are used to mirror variables, that distinction collapses. The code no longer communicates why a value exists or how stable it is meant to be. Well-crafted Terraform draws a bright line between inputs and implementation. Blurring that line does not make the code more flexible; it makes it harder to reason about.

In DevOps, as in any serious craft, restraint matters as much as capability. Terraform locals are powerful, but power without purpose is clutter. If a value is an input, let it remain an input. Save locals for computation, not decoration.

For code examples, see Variables vs Locals

On this page

Ready to unlock value from your data?

With Pythian, you can accomplish your data transformation goals and more.