---
page_title: Upgrading your plugin to use the Packer plugin sdk
sidebar_title: Upgrade Your Plugin to use the Packer plugin sdk
---

# Upgrading your plugin to be compatible with Packer v1.7.0 and later

In version v1.7.0 the Packer plugin development model was split into two separate packages: the Packer core
and the Packer plugin SDK. Prior to version 1.7.0, the Packer core repository (https://github.com/hashicorp/packer) contained the libraries and interfaces used by Packer plugins. In version 1.7.0, these libraries were moved into their own repository (https://github.com/hashicorp/packer-plugin-sdk). If you authored a plugin prior to the v1.7.0 release using the API version 4, you should switch to the Packer Plugin SDK.

## Update plugins to use the new SDK

### Why update to the new SDK?

The goal of the SDK is to clearly separate the Packer core from the Packer plugins; as a plugin maintainer, you should only have to import the SDK and not the core. The SDK will allow us to use semantic versioning to express the changes to the API that our maintainers are expected to use, and will help us keep a clearer promise to you about the location and functionality of our helper tools.

Packer is currently backwards compatible with the old API because the plugin API itself has not changed yet, so if you choose to continue using the old Packer imports, you will be able to do so until you need to upgrade the version of Packer you are importing to create your plugin.

### How to update plugins to use the packer-plugin-SDK

In a best-case scenario, all you'll have to do is update the packer imports to use the packer-plugin-sdk import path

github.com/hashicorp/packer with github.com/hashicorp/packer-plugin-sdk.

But some of the import paths have changed more than that because we've refactored the SDK some to make it easier to discover and use helpful modules. Below are a few common import paths. For a full list of available imports see [Packer Plugin SDK Docs](https://pkg.go.dev/github.com/hashicorp/packer-plugin-sdk/)```

| Old Path | New Path |
| ---------| -------- |
| github.com/hashicorp/packer/template/config | github.com/hashicorp/packer-plugin-sdk/template/config |
| github.com/hashicorp/packer/packer | github.com/hashicorp/packer-plugin-sdk/packer |
| github.com/hashicorp/packer/template/interpolate | github.com/hashicorp/packer-plugin-sdk/template/interpolate |

Here is a more comprehensive list of old imports and their new replacements:

| Old Path | New Path |
| ---------| -------- |
| github.com/hashicorp/packer/helper/builder/testing | github.com/hashicorp/packer-plugin-sdk/acctest |
| **new** | github.com/hashicorp/packer-plugin-sdk/acctest/provisioneracc
| github.com/hashicorp/packer/helper/tests | github.com/hashicorp/packer-plugin-sdk/acctest/testutils |
| github.com/hashicorp/packer/common/adapter | github.com/hashicorp/packer-plugin-sdk/adapter |
| github.com/hashicorp/packer/common/bootcommand | github.com/hashicorp/packer-plugin-sdk/bootcommand |
| github.com/hashicorp/packer/common/chroot | github.com/hashicorp/packer-plugin-sdk/chroot |
| github.com/hashicorp/packer/common | github.com/hashicorp/packer-plugin-sdk/common |
| github.com/hashicorp/packer/helper/communicator | github.com/hashicorp/packer-plugin-sdk/communicator |
| github.com/hashicorp/packer/helper/config | github.com/hashicorp/packer-plugin-sdk/template/config |
| github.com/hashicorp/packer/template/interpolate | github.com/hashicorp/packer-plugin-sdk/template/interpolate |
| github.com/hashicorp/packer/communicator/ssh | github.com/hashicorp/packer-plugin-sdk/communicator/ssh |
| github.com/hashicorp/packer/helper/communicator/sshkey | github.com/hashicorp/packer-plugin-sdk/communicator/sshkey |
| github.com/hashicorp/packer/provisioner | github.com/hashicorp/packer-plugin-sdk/guestexec |
| github.com/hashicorp/packer/common/json | github.com/hashicorp/packer-plugin-sdk/json |
| github.com/hashicorp/packer/helper/multistep | github.com/hashicorp/packer-plugin-sdk/multistep |
| steps from github.com/hashicorp/packer/common | github.com/hashicorp/packer-plugin-sdk/multistep/commonsteps |
| github.com/hashicorp/packer/common/net | github.com/hashicorp/packer-plugin-sdk/net |
| github.com/hashicorp/packer/packer | github.com/hashicorp/packer-plugin-sdk/packer |
| github.com/hashicorp/packer/builder | github.com/hashicorp/packer-plugin-sdk/packerbuilderdata |
| github.com/hashicorp/packer/packer | github.com/hashicorp/packer-plugin-sdk/pathing |
| github.com/hashicorp/packer/packer/plugin | github.com/hashicorp/packer-plugin-sdk/plugin |
| github.com/hashicorp/packer/common/random | github.com/hashicorp/packer-plugin-sdk/random |
| github.com/hashicorp/packer/common | github.com/hashicorp/packer-plugin-sdk/retry |
| github.com/hashicorp/packer/packer/rpc | github.com/hashicorp/packer-plugin-sdk/rpc |
| github.com/hashicorp/packer/communicator | github.com/hashicorp/packer-plugin-sdk/sdk-internals/communicator |
| github.com/hashicorp/packer/common/shell | github.com/hashicorp/packer-plugin-sdk/shell |
| github.com/hashicorp/packer/common/shell-local | github.com/hashicorp/packer-plugin-sdk/shell-local |
| github.com/hashicorp/packer/helper/builder/localexec | github.com/hashicorp/packer-plugin-sdk/shell-local/localexec |
| github.com/hashicorp/packer/common/shutdowncommand | github.com/hashicorp/packer-plugin-sdk/shutdowncommand |
| github.com/hashicorp/packer/template | github.com/hashicorp/packer-plugin-sdk/template |
| github.com/hashicorp/packer/packer/tmp | github.com/hashicorp/packer-plugin-sdk/tmp |
| github.com/hashicorp/packer/helper/useragent | github.com/hashicorp/packer-plugin-sdk/useragent |
| github.com/hashicorp/packer/common/uuid | github.com/hashicorp/packer-plugin-sdk/uuid |
| **new** | github.com/hashicorp/packer-plugin-sdk/version


When in doubt you can search the packer-plugin-sdk repo for the name of your imported structs or functions to see where they exist in the SDK now; we have not changed struct or function names. Or refer to the [Packer Plugin SDK Docs](https://pkg.go.dev/github.com/hashicorp/packer-plugin-sdk/) for help.

## Upgrade plugins to use new multi-plugin rpc server

### Why upgrade to the new rpc server?

The goal of this server is to enable multiple related plugins, for example plugins that share a hypervisor or cloud, to rely on shared libraries without having to submodule common code. The helps maintainers who are experts in a specific technology to focus on that technology without having to maintain several repositories. Having a single global plugin wrapper also helps the Packer core register, download, and install plugins. Finally, it allows more clarity in the plugin binary naming and name-usage within a template.

### Do I have to upgrade?

For now, you do not have to upgrade your plugin, but we recommend doing it. Packer will continue to understand how to discover and launch old-style plugins. However, you will not be able to register your plugin with HashiCorp until you have upgraded the plugin.

### How to upgrade the plugin

We've created a scaffolding repository over at https://github.com/hashicorp/packer-plugin-scaffolding/

If you already have a working plugin, the [builder plugin scaffolding](https://github.com/hashicorp/packer-plugin-scaffolding/tree/main/builder/scaffolding) should look pretty familiar. You'll notice that there are some changes to main.go.

Previously, you may have had a main.go that looks something like:

```golang
package main

import (
  "github.com/hashicorp/packer-plugin-sdk/plugin"
)

func main() {
  server, err := plugin.Server()
  if err != nil {
    panic(err)
  }

  // MyProvisioner fulfils the Provisioner interface and is defined elsewhere
  server.RegisterProvisioner(new(MyProvisioner))
  server.Serve()
}

```

With this single-plugin binary you'd install it by putting it into the plugin directory with the name `packer-provisioner-foo`.


Now, you'll want to use the NewSet() function to create a server. so,

```golang
package main

import (
  "fmt"
  "os"

  "github.com/hashicorp/packer-plugin-sdk/plugin"
)

func main() {
  pps := plugin.NewSet()
  pps.RegisterProvisioner("foo", new(CommentProvisioner))
  err := pps.Run()
  if err != nil {
    fmt.Fprintln(os.Stderr, err.Error())
    os.Exit(1)
  }
}

```

So the implementation is extremely similar, but now we use the "NewSet" function, and call Run() instead of Serve().

With this example, you'd install it by putting it into the plugin directory with the name `packer-plugin-bar`.

In the single binary setup, this you'd have used the name "bar" in your packer template. Now, you need to use the name "bar-foo" in the template.

## Using the Set Architecture for Single Plugins

*** THIS IS ON THE PACKER MASTER BRANCH AND WILL BE AVAILABLE IN V1.7.0

The naming described above could be awkward for users who have given plugins singular names. For example, in a prior world, you may have created a provisioner saved as `packer-provisioner-foo` and accessed it in your template using `"type": "foo"`; Now, if you install a plugin named `packer-plugin-foo`, and register it using NewSet() and RegisterProvisioner() with the name "foo", you'll have to access it in your template using `"type": "foo-foo"` which stutters and breaks backwards compatibility.

To solve this we have a specialized string constant you can use to register your plugins instead:

instead of registering your plugin using

```golang
pps.RegisterProvisioner("foo", new(MyProvisioner))
```

you can register it using

```golang
pps.RegisterProvisioner(plugin.DEFAULT_NAME, new(MyProvisioner))
```

This will tell the Packer core that  when consuming this plugin set, the given plugin should just use the root plugin name, rather than a compound name. Therefore, when accessing a plugin registered this way, you can again reference it in your Packer template using `"type": "foo"`.

## Registering multiple plugins

This is useful where "bar" is the name of the hypervisor or environment, and "foo" is the specific plugin type. Many Packer plugins already follow this naming convention. To use an example from the Packer core; if you were writing a custom VSphere plugin, you could now name the plugin `packer-plugin-vsphere`, and register different VSphere builder plugins using:

```golang
func main() {
  pps := plugin.NewSet()
  pps.RegisterBuilder("iso", new(ISOBuilder))
  pps.RegisterBuilder("clone", new(CloneBuilder))
  err := pps.Run()
  if err != nil {
    fmt.Fprintln(os.Stderr, err.Error())
    os.Exit(1)
  }
}
```

And then reference your plugin in the Packer template using "vsphere-iso" and "vsphere-clone" just like Packer currently does.

You can still use the `DEFAULT_NAME` constant with a set implementation; in this example, whatever you register with the DEFAULT_NAME will be referenced in the Packer template as "vsphere". You can only register one plugin per plugin set using the DEFAULT_NAME

We will soon write a follow-up guide explaining how to register you new plugin set with HashiCorp.
