The Terraform Helm provider lets you deploy Helm charts to Kubernetes as Terraform resources. Instead of running terraform apply for the cluster and helm upgrade for the applications on it, you manage both in one plan, one state file, and one approval path.
This article covers what the Terraform Helm provider is, how to configure it, how to deploy Helm charts with the helm_release resource, how to pass values to a release, and how to migrate from provider v2 to v3, which changed the configuration syntax.
We will cover:
What is Helm?
Helm is the package manager for Kubernetes. It removes the work of configuring and managing individual Kubernetes resources by hand.
You package your applications into charts, distribute them through repositories, and deploy them consistently across environments. You can share, version, and reuse application components instead of maintaining parallel copies of the same manifests.
Read more in our Kustomize vs Helm article.
You can install Helm on your machine for experimentation by following the instructions provided in the official Helm documentation.
What is the Terraform Helm provider?
In Terraform, a provider is a plugin that allows Terraform to interact with a specific infrastructure or service provider. It acts as an interface between Terraform and the target provider, enabling Terraform to create, modify, and manage resources on that platform. Thousands of providers are available for Terraform, covering the major cloud services, Kubernetes, and Helm.
Check out also Terraform Kubernetes provider overview.
The Helm provider deploys software packages into Kubernetes. Configure it with valid cluster credentials before you use it.
The provider has one resource, helm_release, and one data source, helm_template.
How to configure the Terraform Helm provider
Terraform providers are typically distributed as separate plugins that need to be installed and configured in the Terraform environment before they can be used. The provider block in a Terraform configuration file specifies the provider and its required version.
To get started, you’ll need to declare the Helm provider in your Terraform configuration file:
main.tf
terraform {
required_version = ">= 1.0"
required_providers {
helm = {
source = "hashicorp/helm"
version = "~> 3.2"
}
}
}
provider "helm" {
kubernetes = {
config_path = "~/.kube/config" # Path to your Kubernetes config file
}
}Provider v3.0.0 shipped on June 18, 2025 and changed this syntax. kubernetes is now a nested object attribute assigned with =, not a block. The current release is 3.2.0. The v3 provider uses Terraform Plugin Protocol version 6 and requires Terraform 1.0 or later. To keep the old block syntax, pin to 2.17.0.
Notice the config_path option should point to your Kuberentes config file (by default ~/.kube/config) .
To pull charts from a private OCI registry, add a registries list. Repeated registry blocks were replaced by this single list attribute in v3. registries applies to OCI registries only, not to HTTP chart repositories, which you authenticate per release with repository_username and repository_password.
provider "helm" {
kubernetes = {
config_path = "~/.kube/config"
}
registries = [
# Local registry with password protection
{
url = "oci://localhost:5000"
username = var.local_registry_username
password = var.local_registry_password
},
# Private registry
{
url = "oci://private.registry"
username = var.private_registry_username
password = var.private_registry_password
},
]
}How to migrate from Helm provider v2 to v3
Provider v3.0.0 ported the codebase from Terraform Plugin SDKv2 to the Plugin Framework. Every block that used to be written without = is now an attribute. If you upgrade without changing your configuration, terraform plan fails with:
Error: Unsupported block type
on provider-helm.tf line 154, in provider "helm":
154: kubernetes {
Blocks of type "kubernetes" are not expected here. Did you mean to define
argument "kubernetes"? If so, use the equals sign to assign it a value.You will see the same error for Blocks of type “experiments” are not expected here and for set inside helm_release.
| v2 | v3 |
kubernetes { ... } |
kubernetes = { ... } |
registry { ... } repeated |
registries = [ { ... }, { ... } ] |
experiments { ... } |
experiments = { ... } |
set { ... } repeated |
set = [ { ... }, { ... } ] |
set_list { ... } |
set_list = [ { ... } ] |
set_sensitive { ... } |
set_sensitive = [ { ... } ] |
helm_release before:
resource "helm_release" "example" {
name = "example"
chart = "example"
set {
name = "service.type"
value = "ClusterIP"
}
set_sensitive {
name = "api.key"
value = "super-secret-key"
}
}After:
resource "helm_release" "example" {
name = "example"
chart = "example"
set = [
{
name = "service.type"
value = "ClusterIP"
},
]
set_sensitive = [
{
name = "api.key"
value = "super-secret-key"
},
]
}The provider ships a state upgrader, so existing releases migrate without being recreated. Upgrade to at least 3.0.1, which fixed the state upgrader’s handling of the values attribute, and preferably to 3.0.2, which fixed a set of plan inconsistencies found in the initial v3 releases. If you cannot migrate your configuration yet, pin to 2.17.0.
Example — Deploying Helm charts in Kubernetes with Terraform
In your Terraform configuration files, you can now specify the release of the Helm chart you want to deploy using the helm_release resource.
- A chart is a collection of files that describe a set of Kubernetes resources. It includes templates, which define the structure and content of the resources, and a values file that allows for parameterization and configuration customization.
- A release is an instance of a chart running in a Kubernetes cluster. Each release has a unique name and version.
You can find the repository of publicly available Helm packages over on the Artifact hub.
Note: If you follow older tutorials that use https://charts.bitnami.com/bitnami with a pinned chart version, expect image pull failures. Bitnami restructured its public catalog on August 28, 2025: versioned container images moved to docker.io/bitnamilegacy and no longer receive updates, the free tier is a reduced set of hardened images on the latest tag only, and production images moved behind the Bitnami Secure Images subscription. The install path in the bitnami/charts README is now oci://registry-1.docker.io/bitnamicharts/<chart>.
The example below deploys cert-manager:
resource "helm_release" "cert_manager" {
name = "cert-manager"
repository = "https://charts.jetstack.io"
chart = "cert-manager"
version = "v1.21.1"
namespace = "cert-manager"
create_namespace = true
set = [
{
name = "crds.enabled"
value = "true"
},
]
}Example for a Redis cache deployment:
resource "helm_release" "redis" {
name = "my-redis"
repository = "oci://registry-1.docker.io/bitnamicharts"
chart = "redis"
version = "23.1.1"
namespace = "cache"
}Example for monitoring, using the kube-prometheus-stack chart from the Prometheus Community repository:
resource "helm_release" "kube_prometheus_stack" {
name = "kube-prometheus-stack"
repository = "https://prometheus-community.github.io/helm-charts"
chart = "kube-prometheus-stack"
version = "88.1.3"
namespace = "monitoring"
create_namespace = true
}Add supported arguments to helm_release to customize each deployment. The arguments added since provider v3.0.0 are worth knowing:
set_woandset_wo_revision: write-only values that are not persisted to state. Added in v3.0.0 forhelm_releaseand v3.1.0 forhelm_template.take_ownership: lets Helm adopt existing resources not marked as managed by the release. Added in v3.1.0.timeouts: configurable timeouts for create, read, update, and delete. Added in v3.1.0.upgrade_install: the equivalent ofhelm upgrade --install. The provider documentation carries an explicit caution against production use.qps: queries per second against the Kubernetes API, alongside the existingburst_limit. Added in v3.1.0.type = "literal"as a supportedsettype. Added in v3.0.0.
The provider’s only data source is helm_template, which renders chart templates locally and exposes the rendered manifests as attributes. It mirrors the helm template command. Its set, set_list, and set_sensitive arguments changed to list syntax in v3 alongside helm_release:
data "helm_template" "example" {
name = "my-release"
chart = "my-chart"
namespace = "my-namespace"
set = [
{
name = "image.tag"
value = "1.2.3"
},
]
}Read more: Using ArgoCD with Helm charts.
How to pass values to a Helm release
helm_release gives you five ways to supply values. They are not interchangeable.
| Argument | Use it for | State |
values |
Whole YAML documents, usually via file() or templatefile() |
Written to state |
set |
Individual scalar overrides | Written to state |
set_list |
Overrides whose value is a list | Written to state |
set_sensitive |
Scalars you want redacted from plan output | Written to state |
set_wo |
Secrets that must not reach state at all | Not written to state |
set_sensitive hides a value from plan output but still stores it in state. If your concern is the state file rather than the console, use set_wo, and increment set_wo_revision when the value changes so Terraform knows to send the new one.
resource "helm_release" "app" {
name = "app"
chart = "./charts/app"
values = [
templatefile("${path.module}/values.yaml.tftpl", {
replicas = var.replicas
})
]
set = [
{
name = "image.tag"
value = var.image_tag
},
]
set_wo = [
{
name = "database.password"
value = var.database_password
},
]
set_wo_revision = 1
}Managing Terraform resources with Spacelift
Terraform is really powerful, but to achieve an end-to-end secure GitOps approach, you need a platform that can orchestrate your Terraform workflows. Spacelift is the infrastructure orchestration platform built for the AI-accelerated software era.
It manages the full lifecycle for both traditional infrastructure as code (IaC) and AI-provisioned infrastructure, giving you access to a powerful CI/CD workflow and unlocking features such as:
- Policies (based on Open Policy Agent) – You can control how many approvals you need for runs, what kind of resources you can create, and what kind of parameters these resources can have, and you can also control the behavior when a pull request is open or merged.
- Multi-IaC workflows – Combine Terraform with Kubernetes, Ansible, and other IaC tools such as OpenTofu, Pulumi, and CloudFormation, create dependencies among them, and share outputs.
- Build self-service infrastructure – You can use Templates and Blueprints to build self-service infrastructure; simply complete a form to provision infrastructure based on Terraform and other supported tools.
- AI-powered provisioning and diagnostics – Spacelift Intelligence adds an AI-powered layer for natural language provisioning, diagnostics, and operational insight across your infrastructure workflows.
- Integrations with any third-party tools – You can integrate with your favorite third-party tools and even build policies for them. For example, see how to integrate security tools in your workflows using Custom Inputs.
Spacelift enables you to create private workers inside your infrastructure, which helps you execute Spacelift-related workflows on your end. Read the documentation for more information on configuring private workers.
You can check it for free by creating a trial account or requesting a demo with one of our engineers.
Key points
The Terraform Helm provider deploys Helm charts to Kubernetes as Terraform resources. Use it when the cluster and the applications running on it belong in the same Terraform configuration and the same review, rather than in a Terraform run followed by a separate Helm run.
Pin the provider version explicitly. Provider v3 changed the configuration syntax, so an unpinned upgrade from v2 breaks a working configuration. Terraform tracks only the releases it deployed, not changes made directly with the Helm CLI or by a GitOps controller.
Spacelift manages Terraform and Helm workflows with policy as code on every run, drift detection across stacks, and short-lived cloud credentials per run instead of static keys on a local machine. Start a free trial.
Note: Terraform moved to the BUSL license starting with version 1.6, so version 1.5.x and earlier remains open source under MPL 2.0. OpenTofu is an open-source fork of Terraform, created from version 1.5.6, that expands on Terraform’s existing concepts. It is a viable alternative to HashiCorp’s Terraform.
Achieve Terraform at scale with Spacelift
Spacelift takes managing infrastructure at scale to a whole new level, offering a more open, more customizable, and more extensible product. It’s a better, more flexible CI/CD for Terraform, offering maximum security without sacrificing functionality.
Helm Docs. Quickstart Guide. Accessed: 3 August 2026
Terraform Registry. Data Source: helm_template. Accessed: 3 August 2026
Terraform Registry. Helm Provider. Accessed: 3 August 2026
Upgrade Guide for Helm Provider v3.0.0. Accessed: 3 August 2026
Upcoming changes to the Bitnami catalog. Accessed: 3 August 2026

