The most surprising thing about Packer’s source_ami_filter is that it doesn’t actually filter AMIs in the way you’d expect; it filters AMI IDs that Packer finds and then picks the latest one from the filtered set.

Let’s see this in action. Imagine you want to build a new Ubuntu 22.04 LTS AMI, but you only want to use official Ubuntu AMIs and never one that has been modified by someone else. You’d typically start with something like this in your Packer template:

{
  "builders": [
    {
      "type": "amazon-ebs",
      "region": "us-east-1",
      "source_ami_filter": {
        "filters": {
          "name": "ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*",
          "virtualization-type": "hvm",
          "root-device-type": "ebs"
        },
        "owners": ["099720109477"],
        "most_recent": true
      },
      "ssh_username": "ubuntu",

      "ami_name": "my-ubuntu-2204-{{timestamp}}"

    }
  ]
}

Here’s the breakdown of how Packer processes this:

  1. source_ami_filter: This block tells Packer how to find potential base AMIs.
    • filters: These are standard AWS EC2 DescribeImages filters.
      • "name": "ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*": This is a wildcard pattern. Packer will look for AMIs whose names match this pattern. The * is crucial here; it means "any characters."
      • "virtualization-type": "hvm" and "root-device-type": "ebs": These are standard, good practices for modern AMIs.
    • owners: ["099720109477"]. This is the AWS account ID for Canonical (Ubuntu). This is your primary filter for ensuring you’re using official Ubuntu images.
    • most_recent: true: This is the key. After Packer finds all AMIs matching your filters and owners, it will sort them by CreationDate in descending order and pick the very first one.

So, when you run packer build your_template.json, Packer doesn’t just grab an AMI. It performs an EC2 DescribeImages API call with all these criteria. It gets back a list of AMIs. Then, because most_recent is true, it sorts that list by creation date and picks the latest one. This latest AMI becomes the source_ami for your build.

The mental model is that source_ami_filter isn’t about filtering out bad AMIs; it’s about defining the pool from which Packer will select the best candidate. The most_recent: true flag is the selector.

Consider the name filter. If you used "name": "ubuntu-jammy-22.04-amd64-server-20230101", Packer would only look for an AMI with that exact name. If that AMI didn’t exist, or if there was a newer one like ubuntu-jammy-22.04-amd64-server-20230201 and you had most_recent: true, it would still find the newer one. The wildcard * is what allows most_recent to actually find newer versions.

The owners field is incredibly powerful. You can specify your own AWS account ID to ensure you’re only building from existing AMIs you’ve created or approved. You can also use self if you’re in a specific account context, though specifying the account ID is more explicit.

What many people miss is the implicit sorting that happens with most_recent. It’s not just picking any AMI that matches; it’s specifically picking the newest one from the qualifying set. This is why a simple filter like "name": "ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*" combined with owners: ["099720109477"] and most_recent: true reliably gets you the latest official Ubuntu 22.04 AMI.

If you wanted to pin to a specific AMI, you would remove the source_ami_filter block entirely and specify the source_ami directly with the AMI ID.

The next thing you’ll likely encounter is needing to manage multiple source AMI types or regions, which often leads to using Packer’s variables and conditional logic.

Want structured learning?

Take the full Packer course →