Abhinav C

Your Helm chart is a public API. Version it like one.

A Helm chart starts as a convenience for one service. Then a platform team turns it into the shared chart that thirty services install. At that point, values.yaml isn’t configuration anymore. It’s a public API, and the teams installing it are its clients.

Most chart incidents are API incidents that nobody recognized as such: a value renamed, a default changed, a template that now behaves differently for an input nobody tested.

Write the contract down

Helm validates values against a values.schema.json file next to values.yaml, on install, upgrade, lint and template. That makes the schema the contract:

{
  "type": "object",
  "required": ["image"],
  "properties": {
    "replicas": { "type": "integer", "minimum": 1 },
    "image": {
      "type": "object",
      "required": ["repository", "tag"],
      "properties": {
        "repository": { "type": "string" },
        "tag": { "type": "string", "minLength": 1 }
      }
    }
  },
  "additionalProperties": false
}

additionalProperties: false is the important line. Without it, a typo like replica: 3 is silently ignored and the service runs with the default. With it, the install fails and tells you why.

Semantic versioning, honestly

Chart version is the API version, separate from appVersion. Apply semver as if the chart were a library:

  • Patch: template fixes that don’t change rendered output for valid inputs.
  • Minor: new optional values with defaults that keep existing behavior.
  • Major: anything that renames or removes a value, changes a default, or changes rendered resources for existing inputs, such as a new label selector that forces pods to be recreated.

Changing a default is the one teams most often ship as a patch. It’s a breaking change for every consumer who relied on the old default without setting it.

Test what the chart renders

  • Snapshot tests: render the chart with a few representative values files and commit the output. Every pull request shows exactly which Kubernetes resources change. The helm-unittest plugin works well for this.
  • Diff before upgrade: the helm diff plugin shows what an upgrade will change in the cluster before it happens. Make it a required step in deploy pipelines.
  • Policy checks on rendered output, for example that resource requests are set and containers don’t run as root, so the chart can’t produce something the cluster would reject.

Distribute it like an artifact

Push charts to an OCI registry, the same place your images live, and have consumers pin exact versions. Charts in OCI registries have been standard for years, and it’s one less separate chart repository to run and secure.

Keep templates boring

The fastest way to break an API is to make it clever. Every if in a template is a branch someone has to test. When a chart grows an option for every team’s special case, it’s time for a second chart, or for teams to own their own manifests. A chart with fifteen well-documented values beats one with a hundred and fifty that nobody fully understands.

In 2026 more teams are building internal developer platforms on top of charts like these. A platform is only as stable as its interfaces, and for Kubernetes workloads the chart is very often the interface.

Filed under: interfaces that started as a YAML file.

More writing