Skip to main content
Pulumi logo Pulumi logo
  1. Docs
  2. Infrastructure as Code
  3. Concepts
  4. Providers
  5. Any Terraform Provider

Using any Terraform provider

    You can use any Terraform or OpenTofu provider directly in your Pulumi programs. Between them, those ecosystems cover thousands of providers spanning clouds, SaaS platforms, on-premises systems, and internal tooling, and the Any Terraform Provider feature makes them available to Pulumi.

    Reach for it when:

    • No Pulumi provider exists for the service you need, but a Terraform or OpenTofu provider does. This is the most common case, and it covers the long tail of SaaS and infrastructure vendors.
    • Your organization maintains its own Terraform provider. You can point Pulumi at a provider binary on disk, so internal providers work the same way published ones do.
    • You need a provider version that the Pulumi Registry doesn’t publish, such as an older release you’re pinned to or a newer one that isn’t available in the Pulumi Registry yet.

    Language support

    The Any Terraform Provider feature works with every Pulumi language. In every language except Pulumi HCL, pulumi package add is how you add a provider; what differs is whether you also get a generated SDK.

    In TypeScript, Python, Go, .NET, and Java, pulumi package add generates a typed SDK for the provider in your project, so you get autocompletion, type checking, and inline documentation in your editor, the same as with a provider published to the Pulumi Registry.

    In YAML there’s no SDK to generate. pulumi package add records the package in your Pulumi.yaml, and you reference its resources by their schema token, which takes the form <package-name>:<module>:<Resource>.

    Pulumi HCL doesn’t need pulumi package add at all. Terraform and OpenTofu providers resolve from the OpenTofu registry and are bridged automatically, the same way they are in OpenTofu. Declare a provider in a required_providers block if you want to pin its source and version, then run pulumi install.

    Adding a Terraform provider

    Use the pulumi package add command:

    pulumi package add terraform-provider [<registry>/]<author>/<name> [version]
    

    Pulumi resolves providers from the OpenTofu registry by default. That registry is API-compatible with the Terraform registry and mirrors its providers, so in practice a provider published to either one is available. You can also give a fully qualified reference to any server that implements the Terraform registry API.

    Basic example

    To add the HashiCorp random provider:

    pulumi package add terraform-provider hashicorp/random
    

    Along with making the provider available to your program, this adds an entry to your Pulumi.yaml:

    packages:
      random:
        source: terraform-provider
        version: 1.4.0
        parameters:
          - hashicorp/random
    

    Specifying a version

    If you don’t specify a version, Pulumi uses the latest one available from the registry. Pin the version instead so that everyone on your team and every CI run gets the same provider:

    pulumi package add terraform-provider hashicorp/random 3.7.1
    

    The pinned version is recorded in Pulumi.yaml alongside the provider name:

    packages:
      random:
        source: terraform-provider
        version: 1.4.0  # Version of the terraform-provider package
        parameters:
          - hashicorp/random
          - 3.7.1  # Version of the hashicorp/random Terraform provider
    

    Two versions appear here because two things are versioned independently: version is the version of Pulumi’s terraform-provider package, and the second parameter is the version of the Terraform provider it wraps. Pin both for fully reproducible builds.

    Using a provider binary on disk

    For a custom or internal provider that isn’t published to a registry, pass the path to its binary:

    pulumi package add terraform-provider /path/to/my/terraform-provider-binary
    

    Walkthrough

    This walkthrough adds the Honeycomb Terraform provider to a new Pulumi project. Honeycomb is an observability platform whose provider is available to Pulumi through this feature.

    Step 1: Create a new Pulumi project

    pulumi new typescript
    
    pulumi new python
    
    pulumi new go
    
    pulumi new csharp
    
    pulumi new java
    
    pulumi new yaml
    

    Create a directory with a Pulumi.yaml that selects the HCL runtime:

    name: honeycomb-example
    runtime: hcl
    description: Using the Honeycomb Terraform provider with Pulumi
    

    Pulumi HCL takes providers from a required_providers block rather than from pulumi package add, so skip step 2 and go straight to step 3.

    Step 2: Add the Terraform provider

    pulumi package add terraform-provider honeycombio/honeycombio
    

    This downloads the provider and records it in your Pulumi.yaml. In every language except YAML, it also generates and links a typed SDK in your project. Pulumi HCL skips this step.

    Step 3: Use the provider in your code

    import * as pulumi from "@pulumi/pulumi";
    import * as honeycombio from "@pulumi/honeycombio";
    
    const marker = new honeycombio.Marker("deployment-marker", {
        message: "Deployed via Pulumi",
        dataset: "my-dataset"
    });
    
    export const markerId = marker.id;
    
    import pulumi
    import pulumi_honeycombio as honeycombio
    
    marker = honeycombio.Marker(
        "deployment-marker",
        message="Deployed via Pulumi",
        dataset="my-dataset"
    )
    
    pulumi.export("marker_id", marker.id)
    
    package main
    
    import (
        "github.com/pulumi/pulumi-terraform-provider/sdks/go/honeycombio"
        "github.com/pulumi/pulumi/sdk/v3/go/pulumi"
    )
    
    func main() {
        pulumi.Run(func(ctx *pulumi.Context) error {
            marker, err := honeycombio.NewMarker(ctx, "deployment-marker", &honeycombio.MarkerArgs{
                Message: pulumi.String("Deployed via Pulumi"),
                Dataset: pulumi.String("my-dataset"),
            })
            if err != nil {
                return err
            }
    
            ctx.Export("markerId", marker.ID())
            return nil
        })
    }
    
    using Pulumi;
    using Pulumi.Honeycombio;
    
    return await Deployment.RunAsync(() =>
    {
        var marker = new Marker("deployment-marker", new MarkerArgs
        {
            Message = "Deployed via Pulumi",
            Dataset = "my-dataset"
        });
    
        return new Dictionary<string, object?>
        {
            ["markerId"] = marker.Id
        };
    });
    
    package myproject;
    
    import com.pulumi.Context;
    import com.pulumi.Pulumi;
    import com.pulumi.honeycombio.Marker;
    import com.pulumi.honeycombio.MarkerArgs;
    
    public class App {
        public static void main(String[] args) {
            Pulumi.run(App::stack);
        }
    
        public static void stack(Context ctx) {
            var marker = new Marker("deployment-marker", MarkerArgs.builder()
                .message("Deployed via Pulumi")
                .dataset("my-dataset")
                .build());
    
            ctx.export("markerId", marker.id());
        }
    }
    
    name: honeycomb-example
    runtime: yaml
    description: Using the Honeycomb Terraform provider with Pulumi
    resources:
      marker:
        type: honeycombio:Marker
        properties:
          message: Deployed via Pulumi
          dataset: my-dataset
    outputs:
      markerId: ${marker.id}
    packages:
      honeycombio:
        source: terraform-provider
        version: 1.4.0
        parameters:
          - honeycombio/honeycombio
    

    Name the provider’s source in a required_providers block, then run pulumi install:

    terraform {
      required_providers {
        honeycombio = {
          source = "honeycombio/honeycombio"
        }
      }
    }
    
    resource "honeycombio_marker" "deployment_marker" {
      message = "Deployed via Pulumi"
      dataset = "my-dataset"
    }
    
    output "marker_id" {
      value = honeycombio_marker.deployment_marker.id
    }
    

    Step 4: Deploy your infrastructure

    pulumi up
    

    Configuring the provider

    Terraform providers name their configuration fields in snake_case, such as oauth_client_id. Pulumi renders provider configuration keys in camelCase instead, so the same field becomes oauthClientId.

    Provider configuration keys always use the camelCase form, no matter which language your program is written in:

    pulumi config set tailscale:oauthClientId <value>
    

    The same is true everywhere provider configuration is set, including pulumi config set, Pulumi ESC, and the Automation API’s setConfig.

    A snake_case configuration key such as tailscale:oauth_client_id isn’t recognized, and is silently ignored. Always use the camelCase form.

    Resource inputs and outputs are a separate matter. They’re written the way your language writes names, exactly as they are for any other Pulumi provider: clientId in TypeScript, Go, .NET, and Java, and client_id in Python. See Inputs & outputs for more.

    To look up a name, read the provider’s own documentation in the OpenTofu or Terraform registry. Its fields are listed in snake_case, and the Pulumi configuration key is the camelCase form of the same name. To see a provider’s exact configuration keys, run pulumi package get-schema and inspect config.variables.

    Working with your team

    Commit your Pulumi.yaml to source control. It records the provider and its version, which is all a teammate or a CI job needs to reproduce your setup. In Pulumi HCL, the provider is named in your .tf files instead, so commit those along with the sdks/<provider>/hcl.sdk.json descriptor that pulumi install writes for each provider.

    When someone clones the repository, they run pulumi install:

    pulumi install
    

    This installs whatever is missing: the Terraform provider binary, and the generated SDK if the SDK directory isn’t checked in. Provider binaries are cached in a shared location outside your project directory, so each one is downloaded only once per machine.

    Whether to check the generated SDK directory into source control is a tradeoff. See Local SDKs for that decision, along with guidance on upgrading a provider and on team workflow.

    Providers in the Pulumi Registry

    Many of the more popular providers Pulumi makes available this way are also listed in the Pulumi Registry, so you can search for them, read their documentation, and get installation instructions in the same place you’d look for any other Pulumi provider. When you search the Registry, these providers carry a badge identifying them as Any Terraform Provider packages. The Honeycomb provider is one example.

    If the provider you need isn’t in the Pulumi Registry, search the OpenTofu registry and add it with pulumi package add.

    Best practices

    1. Use a Pulumi provider when one exists: A provider published in the Pulumi Registry is maintained, documented, and versioned for Pulumi, so prefer it over adding the Terraform provider directly.
    2. Pin provider versions: Specify a version when you add a provider so that every teammate and CI job gets the same provider. In Pulumi HCL, set version in the provider’s required_providers entry.
    3. Document provider usage: Record which Terraform providers your team uses and why, so they can be revisited when a Pulumi provider becomes available.
    4. Watch for upstream changes: Track the provider’s releases for breaking changes before you upgrade.

    Learn more

      The infrastructure as code platform for any cloud.