DEV Community

Amaresh Pelleti
Amaresh Pelleti

Posted on • Originally published at devtoolhub.com

Terraform Helm Provider Migration: v3 Breaking Changes

Originally published on DevToolHub.

If your terraform plan started throwing schema errors after a routine provider update, you're probably looking at the Terraform Helm provider migration from v2 to v3. HashiCorp rewrote the provider on top of the Terraform Plugin Framework in v3.0.0, and it changed how you write set, kubernetes, and registry configuration — not just internally, but in your actual .tf files.

The latest release is v3.2.0, published June 4, 2026. Here's exactly what changed, the before/after syntax, and the state upgrade errors people are hitting in the GitHub issue tracker.

What the Terraform Helm Provider Migration Changed

Three things break when you jump from v2.x to v3.x:

  1. set, set_list, and set_sensitive inside helm_release and helm_template go from repeatable blocks to a single list attribute of nested objects.
  2. The kubernetes block on the provider becomes a single object attribute (kubernetes = { ... } instead of kubernetes { ... }).
  3. The registry block — which used to support multiple repeated blocks — becomes a registries list attribute.

None of these are cosmetic. Terraform's plugin framework handles blocks and list-of-object attributes differently in state, which is why a straight version bump without touching your HCL will fail to plan.

Why HashiCorp Migrated to the Plugin Framework

The old provider ran on Terraform Plugin SDKv2, which HashiCorp has been retiring across its provider ecosystem in favor of the newer Plugin Framework. The framework uses Terraform Plugin Protocol Version 6, compatible with Terraform 1.0 and above, and gives providers more precise control over schema validation and state handling than SDKv2 allowed.

For the Helm provider specifically, that meant converting the repeatable-block pattern (common in SDKv2-era providers) into list attributes, which the framework models more cleanly. It's the same category of change other HashiCorp providers have gone through — annoying for a version bump, but not unique to Helm.

Migrating set, set_list, and set_sensitive Blocks

This is the change you'll hit in almost every helm_release resource. Before v3, you wrote repeated set blocks:

resource "helm_release" "example" {
  name  = "my-release"
  chart = "my-chart"

  set {
    name  = "service.type"
    value = "ClusterIP"
  }
}
Enter fullscreen mode Exit fullscreen mode

In v3, set is a list of objects instead:

resource "helm_release" "example" {
  name  = "my-release"
  chart = "my-chart"

  set = [
    {
      name  = "service.type"
      value = "ClusterIP"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

The same conversion applies to set_list and set_sensitive — both change from repeated blocks to list-of-object attributes, in both helm_release resources and the helm_template data source. If you have five set blocks in a release today, they collapse into one set = [...] attribute with five entries.

Migrating the kubernetes and registry Blocks

The provider-level configuration changes too. kubernetes goes from a block to a single object:

# Before — v2.x
provider "helm" {
  kubernetes {
    config_path = "~/.kube/config"
  }
}
Enter fullscreen mode Exit fullscreen mode
# After — v3.x
provider "helm" {
  kubernetes = {
    config_path = "~/.kube/config"
  }
}
Enter fullscreen mode Exit fullscreen mode

registry is the trickier one, because it wasn't just a block-to-object change — it also went from singular to plural, since the provider supports multiple registries:

# Before — v2.x
provider "helm" {
  registry {
    url      = "oci://localhost:5000"
    username = "username"
    password = "password"
  }
}
Enter fullscreen mode Exit fullscreen mode
# After — v3.x
provider "helm" {
  registries = [
    {
      url      = "oci://localhost:5000"
      username = "username"
      password = "password"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

If you had multiple registry blocks before, they all move into the same registries list, one object per entry.

State Upgrade Errors During the Terraform Helm Provider Migration

Two issues show up repeatedly in the terraform-provider-helm GitHub tracker. The first: existing state written under v2.x sometimes isn't read correctly after upgrading to v3, because the state upgrader doesn't always cleanly translate the old block-based schema into the new object/list schema. The second, tracked separately, is the provider failing to upgrade resource state to v3 at all in certain configurations.

HashiCorp shipped a hotfix in v3.0.1 (the same day as v3.0.0) specifically for a state upgrader bug affecting the values attribute type — so if you hit an error mentioning values, make sure you're on at least v3.0.1, not v3.0.0.

⚠️ Note: Run terraform plan in a non-production workspace first after the upgrade. If the plan shows unexpected diffs on resources you didn't touch, that's usually the state upgrader mismatch, not a real infrastructure drift. Don't apply until the plan is clean.

Should You Run the Terraform Helm Provider Migration Now

If you're still pinned to a 2.x version, there's no forced deadline, but 2.x isn't getting new features — the changelog shows all active development going into 3.x since mid-2025. The safer path is a deliberate migration rather than an accidental one: pin your provider version explicitly, do the HCL rewrite in a branch, and test the plan against a non-production state before rolling it into your main branch.

If you've already been through a Helm 4 migration on the chart side, this is a smaller lift by comparison — it's syntax, not runtime behavior. The version history since 3.0.0 has been mostly bug fixes and small additive features, not further breaking changes:

  • v3.0.0 (June 18, 2025) — the breaking migration itself
  • v3.0.1 (June 18, 2025) — state upgrader hotfix for values
  • v3.0.2 (June 23, 2025) — fixed plan errors on version specs, postrender execution, sensitive value redaction
  • v3.1.0 (Oct 27, 2025) — added qps, resources, set_wo, take_ownership, configurable operation timeouts
  • v3.1.1 (Nov 17, 2025) — fixed an "inconsistent result after apply" error
  • v3.1.2 (May 21, 2026) — Windows OCI chart fix, dependency updates
  • v3.2.0 (June 4, 2026) — added a linux/s390x build target for IBM Z platforms

Nothing after 3.0.x changes your HCL syntax again — once you've done the initial migration, later upgrades are safe minor bumps.

Frequently Asked Questions

Q: Do I have to migrate to Terraform Helm provider v3?
A: Not immediately, but v2.x isn't receiving new features. If you're managing Helm deployments long-term, plan the migration on your own schedule rather than waiting for a forced upgrade.

Q: My set blocks are gone after upgrading — did I lose configuration?
A: No, but you need to rewrite them as a set = [...] list attribute. The provider won't auto-convert set { } blocks in your .tf files — that part is manual.

Q: What Terraform version does v3 require?
A: 1.0 and above, since it runs on Terraform Plugin Protocol Version 6.

Q: I'm getting a "values" attribute error after upgrading — what's wrong?
A: You're likely on v3.0.0 exactly. Upgrade to at least v3.0.1, which shipped a same-day hotfix for this state upgrader issue.

Quick Summary:

  • Terraform Helm provider v3.0.0 (June 18, 2025) rewrote the provider on the Plugin Framework, requiring Terraform 1.0+
  • set, set_list, and set_sensitive change from repeated blocks to a single list-of-objects attribute
  • kubernetes becomes an object attribute; registry becomes a plural registries list
  • State upgrade errors are common — check GitHub issues #1722 and #1698 if resources don't read correctly post-upgrade
  • Latest version is v3.2.0 (June 4, 2026); no further HCL syntax changes since the 3.0.0 migration

Pin your provider version explicitly before you touch anything, then do the HCL rewrite in a branch you can terraform plan against before merging.

Top comments (0)