Packer Plugins allow new functionality to be added to Packer without modifying the core source code. Packer plugins are able to add new builders, provisioners, hooks, and more. In fact, much of Packer itself is implemented by writing plugins that are simply distributed with Packer. For example, all the builders, provisioners, and more that ship with Packer are implemented as Plugins that are simply hardcoded to load with Packer.

This section will cover how to install and use plugins. If you're interested in developing plugins, the documentation for that is available below, in the developing plugins section.

The current official listing of available Packer plugins can be found here. This is an incomplete list, and more plugins can be found by searching. Typically, searching "packer plugin x" will find what you're looking for if it exists. We hope to create an offical registry for third party plugins in the future.

»How Plugins Work

Packer plugins are completely separate, standalone applications that the core of Packer starts and communicates with.

These plugin applications aren't meant to be run manually. Instead, Packer core executes them as a sub-process, run as a sub-command (packer plugin) and communicates with them. For example, the Shell provisioner is actually run as packer plugin packer-provisioner-shell. The next time you run a Packer build, look at your process list and you should see a handful of packer- prefixed applications running.

»Installing Plugins

The easiest way to install a plugin is to name it correctly, then place it in the proper directory. To name a plugin correctly, make sure the binary is named packer-plugin-NAME. For example, packer-plugin-amazon for a "plugin" binary named "amazon". This binary will make one or more plugins available to use. Valid types for plugins are down this page.

Once the plugin is named properly, Packer automatically discovers plugins in the following directories in the given order. If a conflicting plugin is found later, it will take precedence over one found earlier.

  1. The directory where packer is, or the executable directory.

  2. The $HOME/.packer.d/plugins directory, if $HOME is defined (unix)

  3. The %APPDATA%/packer.d/plugins if %APPDATA% is defined (windows)

  4. The %USERPROFILE%/packer.d/plugins if %USERPROFILE% is defined (windows)

  5. The current working directory.

  6. The directory defined in the env var PACKER_PLUGIN_PATH. There can be more than one directory defined; for example, ~/custom-dir-1:~/custom-dir-2. Separate directories in the PATH string using a colon (:) on posix systems and a semicolon (;) on windows systems. The above example path would be able to find a provisioner named packer-provisioner-foo in either ~/custom-dir-1/packer-provisioner-foo or ~/custom-dir-2/packer-provisioner-foo.

The valid types for plugins are:

  • plugin - A plugin binary that can contain one or more of each Packer plugin type.

  • builder - Plugins responsible for building images for a specific platform.

  • post-processor - A post-processor responsible for taking an artifact from a builder and turning it into something else.

  • provisioner - A provisioner to install software on images created by a builder.

»Developing Plugins

This page will document how you can develop your own Packer plugins. Prior to reading this, it is assumed that you're comfortable with Packer and also know the basics of how Plugins work, from a user standpoint.

Packer plugins must be written in Go, so it is also assumed that you're familiar with the language. This page will not be a Go language tutorial. Thankfully, if you are familiar with Go, the Go toolchain provides many conveniences to help to develop Packer plugins.

»Plugin System Architecture

Packer has a fairly unique plugin architecture. Instead of loading plugins directly into a running application, Packer runs each plugin as a separate application. Inter-process communication and RPC is then used to communicate between the many running Packer processes. Packer core itself is responsible for orchestrating the processes and handles cleanup.

The beauty of this is that your plugin can have any dependencies it wants. Dependencies don't need to line up with what Packer core or any other plugin uses, because they're completely isolated into the process space of the plugin itself.

And, thanks to Go's interfaces, it doesn't even look like inter-process communication is occurring. You just use the interfaces like normal, but in fact they're being executed in a remote process. Pretty cool.

»Plugin Development Basics

Developing a plugin allows you to create additional functionality for Packer. All the various kinds of plugins have a corresponding interface. The plugin needs to implement this interface and expose it using the Packer plugin package (covered here shortly), and that's it!

There are two packages that really matter that every plugin must use. Other than the following two packages, you're encouraged to use whatever packages you want. Because plugins are their own processes, there is no danger of colliding dependencies.

There are two steps involved in creating a plugin:

  1. Implement the desired interface. For example, if you're building a builder plugin, implement the packer.Builder interface.

  2. Serve the interface by calling the appropriate plugin serving method in your main method.

Basic examples are shown below. Note that if you can define a multi-plugin binary as it will allow to add more that one plugin per binary.

import (

// Assume this implements packer.Builder
type ExampleBuilder struct{}

// Assume this implements packer.PostProcessor
type FooPostProcessor struct{}

// Assume this implements packer.Provisioner
type BarProvisioner struct{}

func main() {
    pps := plugin.NewSet()
    pps.RegisterBuilder("example", new(ExampleBuilder))
    pps.RegisterPostProcessor("foo", new(FooPostProcessor))
    pps.RegisterProvisioner("bar", new(BarProvisioner))
    err := pps.Run()
    if err != nil {
        fmt.Fprintln(os.Stderr, err.Error())

That's it! plugin.NewSet handles all the nitty gritty of communicating with Packer core and serving your builder over RPC. It can't get much easier than that.

Here the name of the plugin will be used to use each plugin, so if your plugin is named packer-plugin-my, this would make the following parts available:

  • the my-example builder
  • the my-foo post-processor
  • the my-bar provisioner

Next, just build your plugin like a normal Go application, using go build or however you please. The resulting binary is the plugin that can be installed using standard installation procedures.

The specifics of how to implement each type of interface are covered in the relevant subsections available in the navigation to the left.

»Logging and Debugging

Plugins can use the standard Go log package to log. Anything logged using this will be available in the Packer log files automatically. The Packer log is visible on stderr when the PACKER_LOG environmental is set.

Packer will prefix any logs from plugins with the path to that plugin to make it identifiable where the logs come from. Some example logs are shown below:

2013/06/10 21:44:43 Loading builder: custom
2013/06/10 21:44:43 packer-builder-custom: 2013/06/10 21:44:43 Plugin minimum port: 10000
2013/06/10 21:44:43 packer-builder-custom: 2013/06/10 21:44:43 Plugin maximum port: 25000
2013/06/10 21:44:43 packer-builder-custom: 2013/06/10 21:44:43 Plugin address: :10000

As you can see, the log messages from the custom builder plugin are prefixed with "packer-builder-custom". Log output is extremely helpful in debugging issues and you're encouraged to be as verbose as you need to be in order for the logs to be helpful.

»Plugin Development Tips

Here are some tips for developing plugins, often answering common questions or concerns.

»Naming Conventions

It is standard practice to name the resulting plugin application in the format of packer-plugin-NAME. For example, if you're building a new builder for CustomCloud, it would be standard practice to name the resulting plugin packer-plugin-custom-cloud. This naming convention helps users identify the scope of a plugin.

»Testing Plugins

While developing plugins, you can configure your Packer configuration to point directly to the compiled plugin in order to test it. For example, building the CustomCloud plugin, I may configure packer like so:

  "builders": {
    "custom-cloud": "/an/absolute/path/to/packer-builder-custom-cloud"

This would configure Packer to have the "custom-cloud" plugin, and execute the binary that I am building during development. This is extremely useful during development.

»Distributing Plugins

It is recommended you use a tool like goxc in order to cross-compile your plugin for every platform that Packer supports, since Go applications are platform-specific. goxc will allow you to build for every platform from your own computer.