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 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.
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
- 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.
- 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
versionin the provider’srequired_providersentry. - Document provider usage: Record which Terraform providers your team uses and why, so they can be revisited when a Pulumi provider becomes available.
- Watch for upstream changes: Track the provider’s releases for breaking changes before you upgrade.
Learn more
- Pulumi Registry: Terraform Provider - Installation and configuration guide
- Resource providers - How providers work in Pulumi
- Pulumi packages - Pulumi’s package system
- Local SDKs - Working with locally generated SDKs
- Terraform & OpenTofu integration - Every way Pulumi works with Terraform and OpenTofu
pulumi package add- Command referencepulumi install- Command reference