Reducing Duplication in Packer Builds with HCL2 Variables and Locals
Learn how to use Packer's HCL2 variables and locals to share common settings across multiple builders, keep templates DRY, and switch between environments with a single file.
19 Jul 2026, 22:07 UTC

The Problem: Repeating Settings Across Builders
When you define multiple Amazon Machine Image (AMI) builds in a single Packer template, you often need to specify the same AWS region, instance type, and tags for each builder. Copy‑pasting these values creates duplication that is error‑prone and hard to maintain.
Thesis: Use Variables and Locals to Keep Your Template DRY
By declaring reusable values with variable blocks and computing derived values in a locals block, you can define common settings once and reference them everywhere.
How Variables and Locals Work in HCL2
A variable block declares an input that can be overridden at runtime with -var flags or .auto.pkrvars.hcl files. A locals block lets you assign a name to an expression that is evaluated once during template parsing.
Syntax Overview
variable "environment" {
type = string
default = "dev"
}
locals {
common_tags = {
Environment = var.environment
Owner = "infra-team"
}
aws_region = "us-east-1"
instance_type = "t3.medium"
}
Builders and provisioners then reference these values:
source "amazon-ebs" "example" {
ami_name = "my-app-${var.environment}"
instance_type = local.instance_type
region = local.aws_region
tags = local.common_tags
}
Worked Example: Building Dev and Prod AMIs from One Template
The following template builds an Amazon Linux 2 AMI. The environment name decides the AMI suffix and tags.
variable "environment" {
type = string
default = "dev"
}
locals {
base_ami = {
dev = "ami-0abcdef1234567890"
prod = "ami-0fedcba0987654321"
}[var.environment]
tags = {
Environment = var.environment
Team = "platform"
}
}
source "amazon-ebs" "linux2" {
ami_name = "packer-linux2-${var.environment}"
instance_type = "t3.micro"
region = "us-east-1"
source_ami = local.base_ami
tags = local.tags
}
build {
sources = ["source.amazon-ebs.linux2"]
}
To create the dev AMI, run:
packer build -var='environment=dev' template.pkr.hcl
For prod:
packer build -var='environment=prod' template.pkr.hcl
Trade‑offs and Limitations
- For a single‑image template, adding
variableandlocalsblocks can make the file longer than necessary for newcomers. - A typo in a local name (e.g.,
local.common_tagsinstead oflocal.common_tags) evaluates to an empty value unless you run Packer 1.8+ with strict mode or enable the-var-filevalidation that reports undefined locals as errors. - Over‑reliance on deeply nested locals can obscure where a value originates; keep the block flat and comment complex expressions.
Practical Verification Steps
- Install Packer ≥1.7.0 and configure AWS credentials with permission to
CreateImage,RunInstances, andDeleteSnapshot. - Save the example template as
template.pkr.hclin an empty directory. - Run
packer init .to install the Amazon builder plugin. - Validate syntax:
packer validate .– it should return no errors. - Build the dev image:
packer build -var='environment=dev' .. Check the output for an AMI ID tagged withEnvironment=dev. - Repeat with
-var='environment=prod'and confirm the AMI ID differs and carries the prod tag.
Closing
Leveraging Packer’s HCL2 variable and locals blocks gives you a single source of truth for shared settings, reduces duplication, and lets you switch environments with a simple flag. Start with a small set of common values, move them into a locals block, and replace hard‑coded literals across builders and provisioners. Verify each change with packer validate and a quick build to catch typos early, and you’ll maintain cleaner, more reliable image pipelines as your project scales.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.