Packer’s version fingerprinting is less about tracking what changed in your image and more about tracking which build produced it.

Let’s see it in action. Imagine you’re building an Ubuntu 22.04 image with Packer. Here’s a snippet of a Packer template:

source "amazon-ebs" "ubuntu" {

  ami_name      = "ubuntu-22.04-{{timestamp}}"

  instance_type = "t3.micro"
  region        = "us-east-1"
  source_ami_filter {
    filters = {
      name                = "ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"
      virtualization-type = "hvm"
    }
    most_recent = true
  }
  tags = {
    Name        = "Ubuntu 22.04 Base Image"

    PackerBuild = "{{.Provider}}" // This is where we'll add fingerprinting

  }
}

build {
  sources = ["source.amazon-ebs.ubuntu"]
  provisioner "shell" {
    inline = [

      "echo 'Hello from Packer build {{.BuildVersion}}!' > /etc/build-info.txt",

      "apt-get update && apt-get install -y nginx",
      "systemctl enable nginx"
    ]
  }
}

When Packer runs, it generates a unique identifier for each build. By default, this identifier is not directly embedded into the AMI name or tags in a human-readable way. However, we can leverage built-in Packer variables to create a "fingerprint."

The core idea is to inject information about the build process itself into the image metadata, typically as an AMI tag. This allows you to trace an AMI back to a specific Packer execution.

Here’s how we can enhance the tags block in the amazon-ebs source to include versioning information:

source "amazon-ebs" "ubuntu" {

  ami_name      = "ubuntu-22.04-{{timestamp}}"

  instance_type = "t3.micro"
  region        = "us-east-1"
  source_ami_filter {
    filters = {
      name                = "ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"
      virtualization-type = "hvm"
    }
    most_recent = true
  }
  tags = {
    Name        = "Ubuntu 22.04 Base Image"

    PackerBuild = "{{.Provider}}-{{.BuildVersion}}-{{.BuilderID}}" // Enhanced fingerprint

  }
}

When you run packer build your-template.pkr.hcl, Packer will substitute these variables. Let’s say you run it twice.

The first run might produce an AMI with the tag PackerBuild set to amazon-ebs-1-ca26642a-603c-8b82-1b7b-33c2d8b8b0b2. The second run, even if it uses the exact same Packer template and source AMI, will generate a different PackerBuild tag, perhaps amazon-ebs-2-df3a75b1-714d-9a13-2c8d-44d3e9c9c1b3.

The {{.Provider}} variable tells you which builder was used (e.g., amazon-ebs, docker, googlecompute).

The {{.BuildVersion}} is a sequential number starting from 1 for each builder within a single Packer run. If you have multiple builders, they will each have their own sequence.

The {{.BuilderID}} is a unique UUID generated for each builder instance in a Packer run. This is the most robust part of the fingerprint as it’s highly unlikely to collide.

This means that even if your ami_name looks identical (e.g., ubuntu-22.04-1678886400), the PackerBuild tag will differentiate the exact Packer execution that created it.

The problem this solves is auditing and traceability. When a security vulnerability is found in a deployed instance, you need to know exactly which image it was built from and which version of your build tooling produced that image. Without this, you’re left guessing.

The mental model here is that Packer is a manufacturing line for your infrastructure. The version fingerprint is like a serial number stamped onto each product (your AMI) that tells you which specific machine (Packer execution) and which specific shift (build number within that execution) produced it.

The {{.BuildVersion}} variable is particularly interesting because it resets for each builder. If you have a single builder, it’s 1. If you have two builders in the same template, the first might get 1 and the second 1 as well, but their {{.BuilderID}} will be unique, making the overall fingerprint distinct.

The most surprising thing about Packer’s version fingerprinting is that the most critical part of the fingerprint, the {{.BuilderID}}, is a UUID that is entirely opaque to you until Packer generates it, yet it’s the most reliable way to ensure uniqueness across builds.

The next concept you’ll likely encounter is managing these fingerprints across different environments (dev, staging, prod) and integrating them into your artifact repository or image registry.

Want structured learning?

Take the full Packer course →