Provider Requirements
OpenTF relies on plugins called "providers" to interact with remote systems. OpenTF configurations must declare which providers they require, so that OpenTF can install and use them. This page documents how to declare providers so OpenTF can install them.
Additionally, some providers require configuration (like endpoint URLs or cloud regions) before they can be used. The Provider Configuration page documents how to configure settings for providers.
Requiring Providers
Each module must declare which providers it requires, so that
OpenTF can install and use them. Provider requirements are declared in a
required_providers
block.
A provider requirement consists of a local name, a source location, and a version constraint:
terraform {
required_providers {
mycloud = {
source = "mycorp/mycloud"
version = "~> 1.0"
}
}
}
The required_providers
block must be nested inside the top-level
terraform
block (which can also contain other settings).
Each argument in the required_providers
block enables one provider. The key
determines the provider's local name (its unique identifier
within this module), and the value is an object with the following elements:
source
- the global source address for the provider you intend to use, such ashashicorp/aws
.version
- a version constraint specifying which subset of available provider versions the module is compatible with.
Names and Addresses
Each provider has two identifiers:
- A unique source address, which is only used when requiring a provider.
- A local name, which is used everywhere else in a module.
Local Names
Local names are module-specific, and are assigned when requiring a provider. Local names must be unique per-module.
Outside of the required_providers
block, OpenTF configurations always refer
to providers by their local names. For example, the following configuration
declares mycloud
as the local name for mycorp/mycloud
, then uses that local
name when configuring the provider:
terraform {
required_providers {
mycloud = {
source = "mycorp/mycloud"
version = "~> 1.0"
}
}
}
provider "mycloud" {
# ...
}
Users of a provider can choose any local name for it. However, nearly every
provider has a preferred local name, which it uses as a prefix for all of its
resource types. (For example, resources from hashicorp/aws
all begin with
aws
, like aws_instance
or aws_security_group
.)
Whenever possible, you should use a provider's preferred local name. This makes
your configurations easier to understand, and lets you omit the provider
meta-argument from most of your resources. (If a resource doesn't specify which
provider configuration to use, OpenTF interprets the first word of the
resource type as a local provider name.)
Source Addresses
A provider's source address is its global identifier. It also specifies the primary location where OpenTF can download it.
Source addresses consist of three parts delimited by slashes (/
), as
follows:
[<HOSTNAME>/]<NAMESPACE>/<TYPE>
Hostname (optional): The hostname of the registry that distributes the provider. If omitted, this defaults to
registry.terraform.io
.Namespace: An organizational namespace within the specified registry. In most cases this represents the organization that publishes the provider. This field may have other meanings for other registry hosts.
Type: A short name for the platform or system the provider manages. Must be unique within a particular namespace on a particular registry host.
The type is usually the provider's preferred local name. (There are exceptions; for example,
hashicorp/google-beta
is an alternate release channel forhashicorp/google
, so its preferred local name isgoogle
. If in doubt, check the provider's documentation.)
For example,
the official HTTP provider
belongs to the hashicorp
namespace on registry.terraform.io
, so its
source address is registry.terraform.io/hashicorp/http
or, more commonly, just
hashicorp/http
.
The source address with all three components given explicitly is called the
provider's fully-qualified address. You will see fully-qualified address in
various outputs, like error messages, but in most cases a simplified display
version is used. This display version omits the source host when it is the
public registry, so you may see the shortened version "hashicorp/random"
instead
of "registry.terraform.io/hashicorp/random"
.
-> Note: If you omit the source
argument when requiring a provider,
OpenTF uses an implied source address of
registry.terraform.io/hashicorp/<LOCAL NAME>
.
We recommend using explicit source addresses for all providers.
Handling Local Name Conflicts
Whenever possible, we recommend using a provider's preferred local name, which is usually the same as the "type" portion of its source address.
However, it's sometimes necessary to use two providers with the same preferred local name in the same module, usually when the providers are named after a generic infrastructure type. OpenTF requires unique local names for each provider in a module, so you'll need to use a non-preferred name for at least one of them.
When this happens, we recommend combining each provider's namespace with its type name to produce compound local names with a dash:
terraform {
required_providers {
# In the rare situation of using two providers that
# have the same type name -- "http" in this example --
# use a compound local name to distinguish them.
hashicorp-http = {
source = "hashicorp/http"
version = "~> 2.0"
}
mycorp-http = {
source = "mycorp/http"
version = "~> 1.0"
}
}
}
# References to these providers elsewhere in the
# module will use these compound local names.
provider "mycorp-http" {
# ...
}
data "http" "example" {
provider = hashicorp-http
#...
}
OpenTF won't be able to guess either provider's name from its resource types,
so you'll need to specify a provider
meta-argument for every affected
resource. However, readers and maintainers of your module will be able to easily
understand what's happening, and avoiding confusion is much more important than
avoiding typing.
Version Constraints
Each provider plugin has its own set of available versions, allowing the
functionality of the provider to evolve over time. Each provider dependency you
declare should have a version constraint given in
the version
argument so OpenTF can select a single version per provider
that all modules are compatible with.
The version
argument is optional; if omitted, OpenTF will accept any
version of the provider as compatible. However, we strongly recommend specifying
a version constraint for every provider your module depends on.
To ensure OpenTF always installs the same provider versions for a given configuration, you can use OpenTF CLI to create a dependency lock file and commit it to version control along with your configuration. If a lock file is present, OpenTF CLI, and TACOS (TF Automation and Collaboration Software) will all obey it when installing providers.
Best Practices for Provider Versions
Each module should at least declare the minimum provider version it is known
to work with, using the >=
version constraint syntax:
terraform {
required_providers {
mycloud = {
source = "hashicorp/aws"
version = ">= 1.0"
}
}
}
A module intended to be used as the root of a configuration — that is, as the
directory where you'd run opentf apply
— should also specify the
maximum provider version it is intended to work with, to avoid accidental
upgrades to incompatible new versions. The ~>
operator is a convenient
shorthand for allowing the rightmost component of a version to increment. The
following example uses the operator to allow only patch releases within a
specific minor release:
terraform {
required_providers {
mycloud = {
source = "hashicorp/aws"
version = "~> 1.0.4"
}
}
}
Do not use ~>
(or other maximum-version constraints) for modules you intend to
reuse across many configurations, even if you know the module isn't compatible
with certain newer versions. Doing so can sometimes prevent errors, but more
often it forces users of the module to update many modules simultaneously when
performing routine upgrades. Specify a minimum version, document any known
incompatibilities, and let the root module manage the maximum version.
Built-in Providers
Most providers are distributed separately as plugins, but there
is one provider that is built into OpenTF itself. This provider enables the
the terraform_remote_state
data source.
Because this provider is built in to OpenTF, you don't need to declare it
in the required_providers
block in order to use its features. However, for
consistency it does have a special provider source address, which is
terraform.io/builtin/terraform
. This address may sometimes appear in
OpenTF's error messages and other output in order to unambiguously refer
to the built-in provider, as opposed to a hypothetical third-party provider
with the type name "opentf".
There is also an existing provider with the source address
hashicorp/terraform
, which is an older version of the now-built-in provider.
hashicorp/terraform
is not compatible with OpenTF and should never be declared in a
required_providers
block.
In-house Providers
Anyone can develop and distribute their own providers.
Some organizations develop their own providers to configure proprietary systems, and wish to use these providers from OpenTF without publishing them on a registry.
One option for distributing such a provider is to run an in-house private registry, by implementing the provider registry protocol.
Running an additional service just to distribute a single provider internally may be undesirable, so OpenTF also supports other provider installation methods, including placing provider plugins directly in specific directories in the local filesystem, via filesystem mirrors.
All providers must have a source address that includes (or implies) the hostname of a registry, but that hostname does not need to provide an actual registry service. For in-house providers that you intend to distribute from a local filesystem directory, you can use an arbitrary hostname in a domain your organization controls.
For example, if your corporate domain were example.com
then you might choose
to use opentf.example.com
as your placeholder hostname, even if that
hostname doesn't actually resolve in DNS. You can then choose any namespace and
type you wish to represent your in-house provider under that hostname, giving
a source address like opentf.example.com/examplecorp/ourcloud
:
terraform {
required_providers {
mycloud = {
source = "opentf.example.com/examplecorp/ourcloud"
version = ">= 1.0"
}
}
}
To make version 1.0.0 of this provider available for installation from the local filesystem, choose one of the implied local mirror directories and create a directory structure under it like this:
opentf.example.com/examplecorp/ourcloud/1.0.0
Under that 1.0.0
directory, create one additional directory representing the
platform where you are running OpenTF, such as linux_amd64
for Linux on
an AMD64/x64 processor, and then place the provider plugin executable and any
other needed files in that directory.
Thus, on a Windows system, the provider plugin executable file might be at the following path:
opentf.example.com/examplecorp/ourcloud/1.0.0/windows_amd64/opentf-provider-ourcloud.exe
If you later decide to switch to using a real private provider registry rather
than distribute binaries out of band, you can deploy the registry server at
opentf.example.com
and retain the same namespace and type names, in which
case your existing modules will require no changes to locate the same provider
using your registry server.