In a Helm Chart.yaml, what is the difference between version and appVersion?
answer
- Two versions, two different things
- One is the package, one is the payload
- Only one must be valid SemVer 2
- One names the .tgz and the repo index
- The other lands in app.kubernetes.io/version
basics
~20 sversion is the chart package's own version and must be valid SemVer 2; Helm names the tarball, indexes and resolves the chart from it. appVersion is a free-form label naming the application release the chart ships, and Helm never parses it.
solid answer
~40 s`version` in `Chart.yaml` identifies the *packaging artifact*. It must be SemVer 2, `helm package` names the tarball `<name>-<version>.tgz` from it, a chart repository indexes entries by name plus version, and every publishable change to the chart needs a bump. `appVersion` identifies the *thing being packaged* — the release of the application the chart deploys. It is optional, free-form and never parsed or compared by Helm, so it should be quoted (`appVersion: 1.20` unquoted is a YAML float and renders as `1.2`). It surfaces in `helm list`'s APP VERSION column and in templates as `.Chart.AppVersion`, which the `helm create` scaffold writes into the `app.kubernetes.io/version` label and uses as the default image tag. The two move independently: fixing a probe path bumps `version` alone; shipping a new application build bumps both.
code
yaml · 6 linesapiVersion: v2
name: tile-server
description: A geospatial tile server
type: application
version: 2.14.3
appVersion: "7.9.2"go deeper
Be able to say in one sentence which field describes the chart and which describes the application, and that only the chart's version has to be SemVer. Knowing the two columns helm list prints is enough to pass this screen.
Explain the mechanics: what helm package names the tarball from, why a repository cannot serve two different tarballs at one version, and where .Chart.AppVersion ends up in the scaffold's templates and labels.
Show the release discipline. Say when each field moves, why a published chart version is effectively immutable, and how a version label sourced from appVersion can end up lying once a caller overrides the image tag.
Own the policy: who is allowed to cut a chart version, whether charts version with the application or independently, and how the chart version, the application version and the release revision are correlated across a fleet during an incident.
## Two versions in one file, two different questions `Chart.yaml` is a Helm chart's metadata file, and it carries two fields that both look like a version. `version` is the version of the *chart* — the packaged directory of templates, defaults and helpers. `appVersion` is the version of the *application* that chart installs. Helm ships two fields rather than one because a chart and the software it deploys have independent release cycles: you can fix a chart bug without rebuilding the application, and you can ship a new application build without touching a single template. | Axis | `version` | `appVersion` | |---|---|---| | Describes | the chart package | the application it installs | | Required, and in what form | yes, valid **SemVer 2** | no, and free-form | | Parsed by Helm | yes | never | | Where it surfaces | tarball name, `index.yaml`, CHART column | APP VERSION column, `.Chart.AppVersion` | ## `version` is the packaging artifact Helm requires this field and requires it to be valid SemVer 2 — `MAJOR.MINOR.PATCH`, optionally with a prerelease or build suffix. A chart whose `version` is not parseable SemVer will not load. Everything mechanical hangs off it: `helm package` writes `<name>-<version>.tgz`, a chart repository's `index.yaml` keys each entry by name and version, a version constraint that another chart puts on this one resolves against it, and each release revision records the chart version it was installed from, which is what `helm history` and `helm list`'s CHART column show. Because publishing is keyed on name plus version, `version` is effectively **immutable once published**: a repository already serving `tile-server-2.14.3.tgz` will not notice different content republished under the same coordinates, and consumers get whichever tarball their cache saw first. So every publishable change to the chart — a template fix, a changed default in `values.yaml`, a new helper, a re-pinned subchart — needs a bump. ## `appVersion` is the payload label It is optional, **free-form**, and Helm never parses, compares or sorts it. "Free-form" is literal: `9.2-beta`, `2024.11.3`, a commit SHA, or the string `latest` are all accepted. Because it is free-form it must be **quoted** in YAML, which is why the `helm create` scaffold writes it quoted — an unquoted `appVersion: 1.20` is parsed as a float and renders as `1.2`, and that silently wrong version then travels into a label. What `appVersion` does do is *surface*. `helm list` prints it in the APP VERSION column beside CHART; `helm show chart` prints it; and templates read it as `.Chart.AppVersion`. The scaffold uses it twice: the standard label `app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}`, and as the fallback for the container image tag, so a chart ships a known application build by default while a caller can still override the tag through values. ## How they move together, and how they don't Take a geospatial tile server packaged as chart `tile-server`, currently `version: 2.14.3` / `appVersion: "7.9.2"`. Four cases cover almost every real change: - You correct a readiness probe path in a template. The application is untouched: bump `version` to `2.14.4`, leave `appVersion`. - The tile server team ships build 7.9.3 and the chart needs no edits. Bump both — `appVersion` because the payload moved, `version` because changing `Chart.yaml` at all is a change to the chart, and a repository cannot serve two different `2.14.3` tarballs. - You rename a values key in a way consumers must react to. Bump `version` to `3.0.0`; `appVersion` is irrelevant to that decision, because SemVer here describes the chart's own interface, not the application's. - Nothing changes. Do not re-cut a tarball under an existing `version`; that is the one move that makes a chart repository lie. ## The confusion the question is testing "The version" is one of the most overloaded words around Helm: the chart version, the application version, the `apiVersion` a rendered manifest declares, the Kubernetes version the cluster reports, and the Helm CLI's own version are five different things. A candidate who answers "`version` is the release number" has also collapsed a sixth — the **release revision**, `.Release.Revision`, an integer that Helm increments on every `helm upgrade` and `helm rollback` regardless of which chart version was used. A single release of a 41-service platform chart can sit at revision 38 while the chart is at `2.14.3` and the application at `7.9.2`, and the three numbers have nothing to do with each other. The practical rule to state in an interview: bump `version` for anything you would publish, bump `appVersion` when the software inside changes, and never treat `appVersion` as something Helm can reason about — it is documentation that happens to be machine-readable.
- If only appVersion changes, does anything about the deployed objects change?Only if a template reads `.Chart.AppVersion`. In the standard scaffold it does, twice: the `app.kubernetes.io/version` label and the default image tag, so the rendered manifest changes and the upgrade produces a real diff. If a chart pins the image tag in `values.yaml` instead, moving `appVersion` alone changes nothing but the metadata Helm prints — and that mismatch, a version label disagreeing with the running image, is a common source of confusion during an incident.
- Is defaulting the container image tag to .Chart.AppVersion a good idea?It is the scaffold's default and it keeps chart and application shipping together, which is usually what you want. The costs: a tag is mutable, so it does not pin content the way a digest does; and once a caller overrides the tag, the `app.kubernetes.io/version` label still reports `appVersion` and now lies about what is running. Charts that care usually derive both the tag and the label from the same value so they cannot diverge.
- Why does helm create write appVersion quoted?Because YAML types unquoted scalars. `appVersion: 1.20` is a float, and it renders as `1.2` — the trailing zero disappears into a label or an image tag and the mistake is invisible until someone looks for version 1.20 and cannot find it. Quoting keeps the exact string. `version` is safe unquoted only because SemVer 2 always has three dot-separated parts, which YAML cannot read as a number.
saying these in an interview costs you the question
- Says appVersion must be valid SemVer like version
- Bumps only appVersion after editing templates
- Thinks version is the release revision number
- Claims Helm compares appVersion when resolving charts
- Leaves appVersion unquoted so 1.20 becomes 1.2
- Republishes changed content under the same chart version