---
description: |-
  The provider registry protocol is implemented by a host intending to be the
  origin host for one or more OpenTofu providers, specifying which providers
  are available and where to find their distribution packages.
---

# Provider Registry Protocol

The provider registry protocol is what OpenTofu CLI uses to discover metadata
about providers available for installation and to locate the distribution
packages for a selected provider.

The primary implementation of this protocol is the public
[OpenTofu Registry](https://registry.opentofu.org/) at `registry.opentofu.org`.
By writing and deploying your own implementation of this protocol, you can
create a separate _origin registry_ to distribute your own providers, as an
alternative to publishing them on the public OpenTofu Registry.

This page describes the provider _registry_ protocol, which is the protocol
for finding providers available for installation. It _doesn't_ describe the
API that provider plugins themselves implement to serve requests from OpenTofu
CLI at runtime. For more information on the provider API, see the OpenTofu
SDK documentation.

## Provider Addresses

Each OpenTofu provider has an associated address which uniquely identifies it
within OpenTofu. A provider address has the syntax `hostname/namespace/type`,
where:

* `hostname` is the registry host that the provider is considered to have
  originated from, and the default location OpenTofu will consult for
  information about the provider
  [unless overridden in the CLI configuration](../cli/config/config-file.mdx#provider-installation).
* `namespace` is the name of a namespace, unique on a particular hostname, that
  can contain one or more providers that are somehow related. On the public
  OpenTofu Registry the "namespace" represents the organization that is
  packaging and distributing the provider.
* `type` is the provider type, like "azurerm", "aws", "google", "dns", etc.
  A provider type is unique within a particular hostname and namespace.

The `hostname/` portion of a provider address (including its slash delimiter)
is optional, and if omitted defaults to `registry.opentofu.org/`.

For example:

* `hashicorp/aws` is a shorthand for `registry.opentofu.org/hashicorp/aws`,
  which is the official AWS provider published by HashiCorp.
* `example/foo` is a shorthand for `registry.opentofu.org/example/foo`, which
  is a hypothetical third-party provider published on the public
  OpenTofu Registry.
* `example.com/bar/baz` is a hypothetical third-party provider published at a
  third-party provider registry on `example.com`.

If you intend only to share a provider you've developed for use by all
OpenTofu users, please consider publishing it into the public
[OpenTofu Registry](https://registry.opentofu.org/), which will make your
provider discoverable. You only need to implement this provider registry
protocol if you wish to publish providers whose addresses include a different
hostname that is under your control.

OpenTofu uses the full address (after normalization to always include a
hostname) as its global identifier for providers internally, and so it's
important to note that re-uploading the `examplecorp/azurerm` provider into
another namespace or publishing it on a different hostname will cause OpenTofu
to see it as an entirely separate provider that will _not_ be usable by modules
that declare a dependency on `examplecorp/azurerm`. If your goal is to create
an alternative local distribution source for an existing provider -- that is,
a _mirror_ of the provider -- refer to
[the provider installation method configuration](../cli/config/config-file.mdx#provider-installation)
instead.

## Provider Versions

Each distinct provider address has associated with it a set of versions, each
of which has an associated version number. OpenTofu assumes version numbers
follow the [Semantic Versioning 2.0](https://semver.org/) conventions, with
the schema and behavior of the provider as documented from the perspective of
an end-user of OpenTofu serving as the "public API".

All available versions for a particular provider address are considered to be
the same provider by OpenTofu. Each OpenTofu configuration selects only one
version of each provider for use in the entire configuration, so the version
constraints across all modules are considered together for the purposes of
version selection.

## Service Discovery

The providers protocol begins with OpenTofu CLI using
[OpenTofu's remote service discovery protocol](../internals/remote-service-discovery.mdx),
with the hostname in the provider address acting as the "User-facing Hostname".

The service identifier for the provider registry protocol is `providers.v1`.
Its associated string value is the base URL for the relative URLs defined in
the sections that follow.

For example, the service discovery document for a host that _only_ implements
the provider registry protocol might contain the following:

```json
{
  "providers.v1": "/tofu/providers/v1/"
}
```

If the given URL is a relative URL then OpenTofu will interpret it as relative
to the discovery document itself. The specific provider registry protocol
endpoints are defined as URLs relative to the given base URL, and so the
specified base URL should generally end with a slash to ensure that those
relative paths will be resolved as expected.

The following sections describe the various operations that a provider
registry must implement to be compatible with OpenTofu CLI's provider
installer. The indicated URLs are all relative to the URL resulting from
service discovery, as described above. We use a hypothetical URL for a provider
registry, assuming that the caller already performed service discovery on a hypothetical
`registry.example.io` to learn the base URL.

The URLs are shown with the convention that a path portion with a colon `:`
prefix is a placeholder for a dynamically-selected value, while all other
path portions are literal. For example, in `:namespace/:type/versions`,
the first two path portions are placeholders while the third is literally
the string "versions".

## List Available Versions

This operation determines which versions are currently available for a
particular provider.

| Method | Path                        | Produces           |
| ------ | --------------------------- | ------------------ |
| `GET`  | `:namespace/:type/versions` | `application/json` |

### Parameters

* `namespace` (required): the namespace portion of the address of the requested
  provider.
* `type` (required): the type portion of the address of the requested provider.

### Sample Request

```
curl 'https://registry.opentofu.org/v1/providers/examplecorp/random/versions'
```

### Sample Response

```json
{
  "versions": [
    {
      "version": "2.0.0",
      "protocols": ["4.0", "5.1"],
      "platforms": [
        {"os": "darwin", "arch": "amd64"},
        {"os": "linux", "arch": "amd64"},
        {"os": "linux", "arch": "arm"},
        {"os": "windows", "arch": "amd64"}
      ]
    },
    {
      "version": "2.0.1",
      "protocols": ["5.2"],
      "platforms": [
        {"os": "darwin", "arch": "amd64"},
        {"os": "linux", "arch": "amd64"},
        {"os": "linux", "arch": "arm"},
        {"os": "windows", "arch": "amd64"}
      ]
    }
  ]
}
```

### Response Properties

A successful result is a JSON object containing a single property `versions`.
`versions` is an array of objects that each describe one available version,
with the following properties:

* `version` (required): the version number this object is describing, using
  the semantic versioning string notation. `version` must be unique across
  all objects in the response.
* `protocols` (recommended): an array of OpenTofu provider API versions that
  this version supports, each given in `MAJOR.MINOR` format where each major
  version appears only once and the given minor version is the highest minor
  version supported. For example, `5.1` means that the provider supports both
  protocol `5.0` and protocol `5.1`.

  OpenTofu uses this information, when available, to provide hints to users
  about upgrading or downgrading their version of a particular provider to
  work with their current version of OpenTofu, if their currently-selected
  versions are not compatible.

  Which API versions are supported is, for most providers, decided by which
  version of the Terraform SDK they are built against. Consult the Terraform
  SDK documentation for more information.
* `platforms` (recommended): an array of objects describing platforms that have
  packages available for this version.

  OpenTofu may use this information, when available, to provide hints to
  users about upgrading or downgrading their version of a particular provider
  for compatibility with their current platform.

  The `platforms` objects have properties `os` and `arch`, whose values match
  the properties of the same name in the response to
  [Find a Provider Package](#find-a-provider-package).

Return `404 Not Found` to signal that the registry does not have a provider
with the given namespace and type.

## Find a Provider Package

This operation returns the download URL of and associated metadata about the
distribution package for a particular version of a provider for a particular
operating system and architecture.

OpenTofu CLI uses this operation after it has selected the newest available
version matching the configured version constraints, in order to find the zip
archive containing the plugin itself.

| Method | Path                                           | Produces           |
| ------ | ---------------------------------------------- | ------------------ |
| `GET`  | `:namespace/:type/:version/download/:os/:arch` | `application/json` |

### Parameters

* `namespace` (required): the namespace portion of the address of the requested
  provider.
* `type` (required): the type portion of the address of the requested provider.
* `version` (required): the version selected to download. This will exactly
  match one of the version strings returned from a previous call to
  [List Available Versions](#list-available-versions).
* `os` (required): a keyword identifying the operating system that the returned
  package should be compatible with, like "linux" or "darwin".
* `arch` (required): a keyword identifying the CPU architecture that the
  returned package should be compatible with, like "amd64" or "arm".

### Sample Request

```
curl 'https://registry.opentofu.org/v1/providers/examplecorp/random/2.0.0/download/linux/amd64'
```

### Sample Response

```json
{
  "protocols": ["4.0", "5.1"],
  "os": "linux",
  "arch": "amd64",
  "filename": "terraform-provider-random_2.0.0_linux_amd64.zip",
  "download_url": "https://releases.example.com/terraform-provider-random/2.0.0/terraform-provider-random_2.0.0_linux_amd64.zip",
  "shasums_url": "https://releases.example.com/terraform-provider-random/2.0.0/terraform-provider-random_2.0.0_SHA256SUMS",
  "shasums_signature_url": "https://releases.example.com/terraform-provider-random/2.0.0/terraform-provider-random_2.0.0_SHA256SUMS.sig",
  "shasum": "5f9c7aa76b7c34d722fc9123208e26b22d60440cb47150dd04733b9b94f4541a",
  "signing_keys": {
    "gpg_public_keys": [
      {
        "key_id": "51852D87348FFC4C",
        "ascii_armor": "-----BEGIN PGP PUBLIC KEY BLOCK-----\nVersion: GnuPG v1\n\nmQENBFMORM0BCADBRyKO1MhCirazOSVwcfTr1xUxjPvfxD3hjUwHtjsOy/bT6p9f\nW2mRPfwnq2JB5As+paL3UGDsSRDnK9KAxQb0NNF4+eVhr/EJ18s3wwXXDMjpIifq\nfIm2WyH3G+aRLTLPIpscUNKDyxFOUbsmgXAmJ46Re1fn8uKxKRHbfa39aeuEYWFA\n3drdL1WoUngvED7f+RnKBK2G6ZEpO+LDovQk19xGjiMTtPJrjMjZJ3QXqPvx5wca\nKSZLr4lMTuoTI/ZXyZy5bD4tShiZz6KcyX27cD70q2iRcEZ0poLKHyEIDAi3TM5k\nSwbbWBFd5RNPOR0qzrb/0p9ksKK48IIfH2FvABEBAAG0K0hhc2hpQ29ycCBTZWN1\ncml0eSA8c2VjdXJpdHlAaGFzaGljb3JwLmNvbT6JATgEEwECACIFAlMORM0CGwMG\nCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEFGFLYc0j/xMyWIIAIPhcVqiQ59n\nJc07gjUX0SWBJAxEG1lKxfzS4Xp+57h2xxTpdotGQ1fZwsihaIqow337YHQI3q0i\nSqV534Ms+j/tU7X8sq11xFJIeEVG8PASRCwmryUwghFKPlHETQ8jJ+Y8+1asRydi\npsP3B/5Mjhqv/uOK+Vy3zAyIpyDOMtIpOVfjSpCplVRdtSTFWBu9Em7j5I2HMn1w\nsJZnJgXKpybpibGiiTtmnFLOwibmprSu04rsnP4ncdC2XRD4wIjoyA+4PKgX3sCO\nklEzKryWYBmLkJOMDdo52LttP3279s7XrkLEE7ia0fXa2c12EQ0f0DQ1tGUvyVEW\nWmJVccm5bq25AQ0EUw5EzQEIANaPUY04/g7AmYkOMjaCZ6iTp9hB5Rsj/4ee/ln9\nwArzRO9+3eejLWh53FoN1rO+su7tiXJA5YAzVy6tuolrqjM8DBztPxdLBbEi4V+j\n2tK0dATdBQBHEh3OJApO2UBtcjaZBT31zrG9K55D+CrcgIVEHAKY8Cb4kLBkb5wM\nskn+DrASKU0BNIV1qRsxfiUdQHZfSqtp004nrql1lbFMLFEuiY8FZrkkQ9qduixo\nmTT6f34/oiY+Jam3zCK7RDN/OjuWheIPGj/Qbx9JuNiwgX6yRj7OE1tjUx6d8g9y\n0H1fmLJbb3WZZbuuGFnK6qrE3bGeY8+AWaJAZ37wpWh1p0cAEQEAAYkBHwQYAQIA\nCQUCUw5EzQIbDAAKCRBRhS2HNI/8TJntCAClU7TOO/X053eKF1jqNW4A1qpxctVc\nz8eTcY8Om5O4f6a/rfxfNFKn9Qyja/OG1xWNobETy7MiMXYjaa8uUx5iFy6kMVaP\n0BXJ59NLZjMARGw6lVTYDTIvzqqqwLxgliSDfSnqUhubGwvykANPO+93BBx89MRG\nunNoYGXtPlhNFrAsB1VR8+EyKLv2HQtGCPSFBhrjuzH3gxGibNDDdFQLxxuJWepJ\nEK1UbTS4ms0NgZ2Uknqn1WRU1Ki7rE4sTy68iZtWpKQXZEJa0IGnuI2sSINGcXCJ\noEIgXTMyCILo34Fa/C6VCm2WBgz9zZO8/rHIiQm1J5zqz0DrDwKBUM9C\n=LYpS\n-----END PGP PUBLIC KEY BLOCK-----",
        "trust_signature": "",
        "source": "ExampleCorp",
        "source_url": "https://www.examplecorp.com/security.html"
      }
    ]
  },
  "packages": {
    "darwin_amd64": {
      "hashes": [
        "zh:fa36a9bfe2f1532af36af30ab607f2858aef6ae73754349123fe140f9bef0701",
        "h1:yZ6W9xVRg/J+CsYC5zefHGnaygOxVVCk34uidFslHV4="
      ],
      "package_size": 6555985
    },
    "darwin_arm64": {
      "hashes": [
        "zh:b4798fb4b1171ee66435212dc633c1836ed38314566c67a2a29d2d426b020a77",
        "h1:Q1NTszPWmiltpevj7SqfEL3GnYby/13i4oKGEWkJCKM="
      ],
      "package_size": 6184593
    }
  }
}
```

### Response Properties

A successful result is a JSON object with the following properties:

* `protocols` (required): an array of OpenTofu provider API versions that
  the provider supports, in the same format as for
  [List Available Versions](#list-available-versions).

  While this property is optional when listing available options, it is
  _required_ for describing an individual provider package so that OpenTofu
  CLI can avoid downloading a package that will not be compatible with it.

* `os` (required): this must echo back the `os` parameter from the
  request.

* `arch` (required): this must echo back the `arch` parameter from the
  request. 

* `filename` (required): the filename for this provider's zip archive as
  recorded in the "shasums" document, so that OpenTofu CLI can determine which
  of the given checksums should be used for this specific package.

* `download_url` (required): a URL from which OpenTofu can retrieve the
  provider's zip archive. If this is a relative URL then it will be resolved
  relative to the URL that returned the containing JSON object.

* `shasums_url` (required): a URL from which OpenTofu can retrieve a text
  document recording expected SHA256 checksums for this package and possibly
  other packages for the same provider version on other platforms.

  The indicated document must be in the format generated by the `sha256`
  command available on many Unix systems, with one entry recording the
  same filename given in the `filename` property (case sensitive).

* `shasums_signature_url` (required): a URL from which OpenTofu can retrieve
  a binary, detached GPG signature for the document at `shasums_url`, signed
  by one of the keys indicated in the `signing_keys` property.
  
* `shasum` (required): the SHA256 checksum for this provider's zip archive as
  recorded in the shasums document.

* `signing_keys` (required): an object describing signing keys for this
  provider package, one of which must have been used to produce the signature
  at `shasums_signature_url`. The object has the following nested properties:

  * `gpg_public_keys` (required): an array of objects, each describing one
    GPG signing key that is allowed to sign the checksums for this provider
    version. At least one element must be included, representing the key that
    produced the signature at `shasums_signature_url`. These objects have
    the following nested properties:

    * `key_id` (required): uppercase-hexadecimal-formatted ID for this GPG key

    * `ascii_armor` (required): an "ascii-armor" encoding of the **public key**
      associated with this GPG key.
* `packages` (recommended): platform specific package metadata to assist in
  provider locking.
  * `hashes` (required): List of valid hashes for the specific provider package.
  * `package_size` (required): Size in bytes of the specific provider package.
    Used to help prevent hash collision attacks.
    
    If `packages` is included then the information for all platforms must be included regardless of which platform was requested, because the included checksums will typically be copied into a dependency lock file for verifying packages installed on other platforms in future. The entry for each platform must include at least a `zh:` hash matching the value that would be returned in the top-level `shasum` property when requesting that platform.

Return `404 Not Found` to signal that the given provider version isn't
available for the requested operating system and/or architecture. OpenTofu
CLI will only attempt to download versions that it has previously seen in
response to [List Available Versions](#list-available-versions).
