terraform/website/docs/language/providers/requirements.html.md

17 KiB

layout page_title
language Provider Requirements - Configuration Language

Provider Requirements

-> Note: This page is about a feature of Terraform 0.13 and later; it also describes how to use the more limited version of that feature that was available in Terraform 0.12.

Terraform relies on plugins called "providers" to interact with remote systems.

Terraform configurations must declare which providers they require, so that Terraform can install and use them. Additionally, some providers require configuration (like endpoint URLs or cloud regions) before they can be used.

  • This page documents how to declare providers so Terraform can install them.

  • The Provider Configuration page documents how to configure settings for providers.

Requiring Providers

Each Terraform module must declare which providers it requires, so that Terraform 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 as hashicorp/aws.

  • version - a version constraint specifying which subset of available provider versions the module is compatible with.

-> Note: The name = { source, version } syntax for required_providers was added in Terraform v0.13. Previous versions of Terraform used a version constraint string instead of an object (like mycloud = "~> 1.0"), and had no way to specify provider source addresses. If you want to write a module that works with both Terraform v0.12 and v0.13, see v0.12-Compatible Provider Requirements below.

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 Terraform module.

-> Note: Prior to Terraform 0.13, providers only had local names, since Terraform could only automatically download providers distributed by HashiCorp.

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, Terraform 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, Terraform 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 Terraform can download it.

Source addresses consist of three parts delimited by slashes (/), as follows:

[<HOSTNAME>/]<NAMESPACE>/<TYPE>

  • Hostname (optional): The hostname of the Terraform registry that distributes the provider. If omitted, this defaults to registry.terraform.io, the hostname of the public Terraform Registry.

  • Namespace: An organizational namespace within the specified registry. For the public Terraform Registry and for Terraform Cloud's private registry, 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 for hashicorp/google, so its preferred local name is google. 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, Terraform uses an implied source address of registry.terraform.io/hashicorp/<LOCAL NAME>. This is a backward compatibility feature to support the transition to Terraform 0.13; in modules that require 0.13 or later, 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. Terraform 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
  #...
}

Terraform 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 Terraform can select a single version per provider that all modules are compatible with.

The version argument is optional; if omitted, Terraform 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 Terraform always installs the same provider versions for a given configuration, you can use Terraform CLI to create a dependency lock file and commit it to version control along with your configuration. If a lock file is present, Terraform Cloud, CLI, and Enterprise will all obey it when installing providers.

Hands-on: Try the Lock and Upgrade Provider Versions tutorial on HashiCorp Learn.

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 terraform 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 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

While most Terraform providers are distributed separately as plugins, there is currently one provider that is built in to Terraform itself, which provides the terraform_remote_state data source.

Because this provider is built in to Terraform, 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 Terraform'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 "terraform".

There is also an existing provider with the source address hashicorp/terraform, which is an older version of the now-built-in provider that was used by older versions of Terraform. hashicorp/terraform is not compatible with Terraform v0.11 or later and should never be declared in a required_providers block.

In-house Providers

Anyone can develop and distribute their own Terraform providers. See the Call APIs with Terraform Providers collection on HashiCorp Learn for more about provider development.

Some organizations develop their own providers to configure proprietary systems, and wish to use these providers from Terraform without publishing them on the public Terraform 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 Terraform 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 terraform.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 terraform.example.com/examplecorp/ourcloud:

terraform {
  required_providers {
    mycloud = {
      source  = "terraform.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:

terraform.example.com/examplecorp/ourcloud/1.0.0

Under that 1.0.0 directory, create one additional directory representing the platform where you are running Terraform, 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:

terraform.example.com/examplecorp/ourcloud/1.0.0/windows_amd64/terraform-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 terraform.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.

v0.12-Compatible Provider Requirements

Explicit provider source addresses were introduced with Terraform v0.13, so the full provider requirements syntax is not supported by Terraform v0.12.

However, in order to allow writing modules that are compatible with both Terraform v0.12 and v0.13, versions of Terraform between v0.12.26 and v0.13 will accept but ignore the source argument in a required_providers block.

Consider the following example written for Terraform v0.13:

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 1.0"
    }
  }
}

Terraform v0.12.26 will accept syntax like the above but will understand it in the same way as the following v0.12-style syntax:

terraform {
  required_providers {
    aws = "~> 1.0"
  }
}

In other words, Terraform v0.12.26 ignores the source argument and considers only the version argument, using the given local name as the un-namespaced provider type to install.

When writing a module that is compatible with both Terraform v0.12.26 and Terraform v0.13.0 or later, you must follow the following additional rules so that both versions will select the same provider to install:

  • Use only providers that can be automatically installed by Terraform v0.12. Third-party providers, such as community providers in the Terraform Registry, cannot be selected by Terraform v0.12 because it does not support the hierarchical source address namespace.

  • Ensure that your chosen local name exactly matches the "type" portion of the source address given in the source argument, such as both being "aws" in the examples above, because Terraform v0.12 will use the local name to determine which provider plugin to download and install.

  • If the provider belongs to the hashicorp namespace, as with the hashicorp/aws provider shown above, omit the source argument and allow Terraform v0.13 to select the hashicorp namespace by default.

  • Provider type names must always be written in lowercase. Terraform v0.13 treats provider source addresses as case-insensitive, but Terraform v0.12 considers its legacy-style provider names to be case-sensitive. Using lowercase will ensure that the name is selectable by both Terraform major versions.

This compatibility mechanism is provided as a temporary transitional aid only. When Terraform v0.12 detects a use of the new source argument it doesn't understand, it will emit a warning to alert the user that it is disregarding the source address given in that argument.