> For the complete documentation index, see [llms.txt](https://developer.harness.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developer.harness.io/artifact-registry/new-to-artifact-registry/quickstart/terraform-quickstart.md).

# Terraform

{% @harness-package-selector/package-selector platforms="%5B%7B%22label%22%3A%22Docker%22%2C%22slug%22%3A%22docker%22%2C%22path%22%3A%22artifact-registry%2Fnew-to-artifact-registry%2Fquickstart%2Fdocker-quickstart%22%7D%2C%7B%22label%22%3A%22Helm%22%2C%22slug%22%3A%22helm%22%2C%22path%22%3A%22artifact-registry%2Fnew-to-artifact-registry%2Fquickstart%2Fhelm-quickstart%22%7D%2C%7B%22label%22%3A%22Helm%20HTTP%22%2C%22slug%22%3A%22helm-http%22%2C%22path%22%3A%22artifact-registry%2Fnew-to-artifact-registry%2Fquickstart%2Fhelm-http-quickstart%22%7D%2C%7B%22label%22%3A%22Generic%22%2C%22slug%22%3A%22generic%22%2C%22path%22%3A%22artifact-registry%2Fnew-to-artifact-registry%2Fquickstart%2Fgeneric-quickstart%22%7D%2C%7B%22label%22%3A%22Raw%20File%22%2C%22slug%22%3A%22raw-file%22%2C%22path%22%3A%22artifact-registry%2Fnew-to-artifact-registry%2Fquickstart%2Fraw-file-quickstart%22%7D%2C%7B%22label%22%3A%22Maven%22%2C%22slug%22%3A%22maven%22%2C%22path%22%3A%22artifact-registry%2Fnew-to-artifact-registry%2Fquickstart%2Fmaven-quickstart%22%7D%2C%7B%22label%22%3A%22Python%22%2C%22slug%22%3A%22python%22%2C%22path%22%3A%22artifact-registry%2Fnew-to-artifact-registry%2Fquickstart%2Fpython-quickstart%22%7D%2C%7B%22label%22%3A%22NPM%22%2C%22slug%22%3A%22npm%22%2C%22path%22%3A%22artifact-registry%2Fnew-to-artifact-registry%2Fquickstart%2Fnpm-quickstart%22%7D%2C%7B%22label%22%3A%22Nuget%22%2C%22slug%22%3A%22nuget%22%2C%22path%22%3A%22artifact-registry%2Fnew-to-artifact-registry%2Fquickstart%2Fnuget-quickstart%22%7D%2C%7B%22label%22%3A%22RPM%22%2C%22slug%22%3A%22rpm%22%2C%22path%22%3A%22artifact-registry%2Fnew-to-artifact-registry%2Fquickstart%2Frpm-quickstart%22%7D%2C%7B%22label%22%3A%22Debian%22%2C%22slug%22%3A%22debian%22%2C%22path%22%3A%22artifact-registry%2Fnew-to-artifact-registry%2Fquickstart%2Fdebian-quickstart%22%7D%2C%7B%22label%22%3A%22Alpine%22%2C%22slug%22%3A%22alpine%22%2C%22path%22%3A%22artifact-registry%2Fnew-to-artifact-registry%2Fquickstart%2Falpine-quickstart%22%7D%2C%7B%22label%22%3A%22Wolfi%22%2C%22slug%22%3A%22wolfi%22%2C%22path%22%3A%22artifact-registry%2Fnew-to-artifact-registry%2Fquickstart%2Fwolfi-quickstart%22%7D%2C%7B%22label%22%3A%22Cargo%22%2C%22slug%22%3A%22cargo%22%2C%22path%22%3A%22artifact-registry%2Fnew-to-artifact-registry%2Fquickstart%2Fcargo-quickstart%22%7D%2C%7B%22label%22%3A%22Conan%22%2C%22slug%22%3A%22conan%22%2C%22path%22%3A%22artifact-registry%2Fnew-to-artifact-registry%2Fquickstart%2Fconan-quickstart%22%7D%2C%7B%22label%22%3A%22Go%22%2C%22slug%22%3A%22go%22%2C%22path%22%3A%22artifact-registry%2Fnew-to-artifact-registry%2Fquickstart%2Fgo-quickstart%22%7D%2C%7B%22label%22%3A%22Hugging%20Face%22%2C%22slug%22%3A%22hugging-face%22%2C%22path%22%3A%22artifact-registry%2Fnew-to-artifact-registry%2Fquickstart%2Fhugging-face-quickstart%22%7D%2C%7B%22label%22%3A%22Conda%22%2C%22slug%22%3A%22conda%22%2C%22path%22%3A%22artifact-registry%2Fnew-to-artifact-registry%2Fquickstart%2Fconda-quickstart%22%7D%2C%7B%22label%22%3A%22Dart%22%2C%22slug%22%3A%22dart%22%2C%22path%22%3A%22artifact-registry%2Fnew-to-artifact-registry%2Fquickstart%2Fdart-quickstart%22%7D%2C%7B%22label%22%3A%22PHP%20Composer%22%2C%22slug%22%3A%22php-composer%22%2C%22path%22%3A%22artifact-registry%2Fnew-to-artifact-registry%2Fquickstart%2Fphp-composer-quickstart%22%7D%2C%7B%22label%22%3A%22Swift%22%2C%22slug%22%3A%22swift%22%2C%22path%22%3A%22artifact-registry%2Fnew-to-artifact-registry%2Fquickstart%2Fswift-quickstart%22%7D%2C%7B%22label%22%3A%22Puppet%22%2C%22slug%22%3A%22puppet%22%2C%22path%22%3A%22artifact-registry%2Fnew-to-artifact-registry%2Fquickstart%2Fpuppet-quickstart%22%7D%2C%7B%22label%22%3A%22Terraform%22%2C%22slug%22%3A%22terraform%22%2C%22path%22%3A%22artifact-registry%2Fnew-to-artifact-registry%2Fquickstart%2Fterraform-quickstart%22%7D%2C%7B%22label%22%3A%22R%20(CRAN)%22%2C%22slug%22%3A%22r-cran%22%2C%22path%22%3A%22artifact-registry%2Fnew-to-artifact-registry%2Fquickstart%2Fr-cran-quickstart%22%7D%2C%7B%22label%22%3A%22RubyGems%22%2C%22slug%22%3A%22rubygems%22%2C%22path%22%3A%22artifact-registry%2Fnew-to-artifact-registry%2Fquickstart%2Frubygems-quickstart%22%7D%5D" selectedPlatform="terraform" %}

Use a **Terraform** registry to host private Terraform modules and providers.

***

### Before you begin <a href="#before-you-begin" id="before-you-begin"></a>

* Ensure you have the Terraform CLI (`terraform`) installed on your local machine.
* Access to a Harness account with appropriate permissions to create registries and connectors.

***

### Create a Terraform artifact registry <a href="#create-a-terraform-artifact-registry" id="create-a-terraform-artifact-registry"></a>

1. Go to the Artifact Registry module in your Harness project.
2. Click **New Artifact Registry**.
3. In the Registry Type list, select **Terraform**.
4. Enter a **Registry Name**.

   <div data-gb-custom-block data-tag="hint" data-style="info" class="hint hint-info"><p><strong>REGISTRY NAME CRITERIA</strong></p><p>The registry name must start with a letter, should only contain lowercase alphanumerics, <code>_</code>, <code>.</code> and <code>-</code>, and <em>must be unique to your Harness account</em>.</p></div>
5. Optionally, add a Description and Labels for better organization.
6. Choose visibility between **Public** and **Private**. *By default, the visibility is set to Private*.
7. Select **Create Registry** to finalize.

***

### Configure an upstream proxy (optional) <a href="#configure-an-upstream-proxy-optional" id="configure-an-upstream-proxy-optional"></a>

An upstream proxy allows your registry to fetch Terraform modules and providers from external Terraform-protocol registries when they are not available locally. The default upstream is `registry.terraform.io`.

#### Create an upstream proxy <a href="#create-an-upstream-proxy" id="create-an-upstream-proxy"></a>

1. In the Artifact Registry module, select the dropdown next to **New Artifact Registry** and select **Upstream Proxy**.
2. Select **Terraform** as the proxy type.
3. Enter an **Upstream Proxy Key**.
4. Optionally, add a Description and Labels.
5. Select your **Source**:
   * Terraform Registry
   * Custom
6. If you choose Custom, enter your **Remote Registry URL** (for example, `https://registry.terraform.io`).
7. Choose your **Authentication** method (`Anonymous` by default for public Terraform registries).
8. Click **Create Upstream Proxy** to establish the connection.

#### Configure the upstream proxy in your registry <a href="#configure-the-upstream-proxy-in-your-registry" id="configure-the-upstream-proxy-in-your-registry"></a>

1. In the Artifact Registry module, select an existing Terraform Artifact Registry.
2. Go to the **Configuration** tab.
3. In the **Advanced (Optional)** section, click **Configure Upstream**.
4. Select from the list of compatible proxies to add them to your registry.
5. Select **Save** to save the configuration.

{% hint style="info" %}
**UPSTREAM PROXY CACHING**

If a module or provider is not found in your Harness registry, the upstream proxy fetches it from the remote registry and caches it.
{% endhint %}

***

### Set up the Terraform client <a href="#set-up-the-terraform-client" id="set-up-the-terraform-client"></a>

In your Harness Terraform Artifact Registry, click **Set Up Client** and follow the instructions to configure Terraform or OpenTofu to use the registry.

#### Configure a module <a href="#configure-a-module" id="configure-a-module"></a>

{% tabs %}
{% tab title="Terraform CLI" %}
**1. Generate identity token**

1. In your Harness Terraform Artifact Registry, click **Set Up Client**.
2. Click **Generate Token** to generate an identity token.

**2. Configure \~/.terraformrc**

Add the following to `~/.terraformrc`:

```bash
host "pkg.harness.io" {
  services = {
    "modules.v1" = "https://pkg.harness.io/pkg/<ACCOUNT_ID>/<REGISTRY_NAME>/terraform/v1/modules/"
  }
}

credentials "pkg.harness.io" {
  token = "<API_KEY>"
}
```

**3. Upload module**

Upload the module directory to the registry:

```bash
hc artifact push terraform <REGISTRY_NAME> <MODULE_DIR> --namespace <NAMESPACE> --name <NAME> --provider <PROVIDER> --version <VERSION>
```

**4. Use module**

1. Reference the module in your `.tf` file:

```bash
module "example" {
  source  = "pkg.harness.io/<NAMESPACE>/<NAME>/<PROVIDER>"
  version = "<VERSION>"
}
```

2. Run `terraform init`.
   {% endtab %}

{% tab title="OpenTofu" %}
**1. Generate identity token**

1. In your Harness Terraform Artifact Registry, click **Set Up Client**.
2. Click **Generate Token** to generate an identity token.

**2. Configure \~/.tofurc**

Add the following to `~/.tofurc`:

```bash
host "pkg.harness.io" {
  services = {
    "modules.v1" = "https://pkg.harness.io/pkg/<ACCOUNT_ID>/<REGISTRY_NAME>/terraform/v1/modules/"
  }
}

credentials "pkg.harness.io" {
  token = "<API_KEY>"
}
```

**3. Upload module**

Upload the module directory to the registry:

```bash
hc artifact push terraform <REGISTRY_NAME> <MODULE_DIR> --namespace <NAMESPACE> --name <NAME> --provider <PROVIDER> --version <VERSION>
```

**4. Use module**

1. Reference the module in your `.tf` file:

```hcl
module "example" {
  source  = "pkg.harness.io/<NAMESPACE>/<NAME>/<PROVIDER>"
  version = "<VERSION>"
}
```

2. Run `tofu init`.
   {% endtab %}
   {% endtabs %}

#### Configure a provider <a href="#configure-a-provider" id="configure-a-provider"></a>

{% tabs %}
{% tab title="Terraform CLI" %}
**1. Generate identity token**

1. In your Harness Terraform Artifact Registry, click **Set Up Client**.
2. Click **Generate Token** to generate an identity token.

**2. Configure \~/.terraformrc**

Add the following to `~/.terraformrc`:

```bash
credentials "pkg.harness.io" {
  token = "<API_KEY>"
}

provider_installation {
  network_mirror {
    url = "https://pkg.harness.io/pkg/<ACCOUNT_ID>/<REGISTRY_NAME>/terraform/v1/providers/"
  }
  direct {
    exclude = ["registry.terraform.io/*/*"]
  }
}
```

**3. Upload provider**

Upload a provider binary to the registry:

```bash
hc artifact push terraform <REGISTRY_NAME> <FILE_PATH> --namespace <NAMESPACE>
```

**4. Use provider**

1. Reference the provider in your `.tf` file:

```bash
terraform {
  required_providers {
    <TYPE> = {
      source  = "<NAMESPACE>/<TYPE>"
      version = "<VERSION>"
    }
  }
}
```

2. Run `terraform init`.
   {% endtab %}

{% tab title="OpenTofu" %}
**1. Generate identity token**

1. In your Harness Terraform Artifact Registry, click **Set Up Client**.
2. Click **Generate Token** to generate an identity token.

**2. Configure \~/.tofurc**

Add the following to `~/.tofurc`:

```bash
credentials "pkg.harness.io" {
  token = "<API_KEY>"
}

provider_installation {
  network_mirror {
    url = "https://pkg.harness.io/pkg/<ACCOUNT_ID>/<REGISTRY_NAME>/terraform/v1/providers/"
  }
  direct {
    exclude = ["registry.terraform.io/*/*"]
  }
}
```

**3. Upload provider**

Upload a provider binary to the registry:

```bash
hc artifact push terraform <REGISTRY_NAME> <FILE_PATH> --namespace <NAMESPACE>
```

**4. Use provider**

1. Reference the provider in your `.tf` file:

```hcl
terraform {
  required_providers {
    <TYPE> = {
      source  = "<NAMESPACE>/<TYPE>"
      version = "<VERSION>"
    }
  }
}
```

2. Run `tofu init`.
   {% endtab %}
   {% endtabs %}

***

### Troubleshooting <a href="#troubleshooting" id="troubleshooting"></a>

<details>

<summary>Publish to a Terraform registry returns 409 Conflict</summary>

Module and provider versions are immutable after publish. Choose a new SemVer version, or delete the existing version only if your registry retention and lifecycle policies allow it.

</details>
