What does helm push upload to an OCI registry, and where does the target reference come from?
answer
- It will not take a directory
- The destination stops one segment short
- Metadata inside the archive decides
- A neighbouring file goes too
- Nothing left to regenerate afterwards
basics
~20 shelm push takes an already-packaged .tgz and a base registry path. The chart name and version come from Chart.yaml inside the archive, not from the command, so the destination omits both. If a matching .prov file sits beside the .tgz it is uploaded alongside automatically.
solid answer
~40 s`helm push tileserver-2.7.14.tgz oci://registry.example.internal/platform-charts` publishes a chart. Two things surprise people. First, **push takes a packaged archive, not a chart directory** — run `helm package` first. Second, **the destination is the base path only**: Helm reads `name` and `version` from the `Chart.yaml` inside the archive and appends them, so the chart lands at `.../platform-charts/tileserver` tagged `2.7.14`. Renaming the file changes nothing; the metadata inside decides. If a provenance file named `tileserver-2.7.14.tgz.prov` sits next to the archive, Helm uploads it alongside the chart automatically, so a consumer can verify later. There is no index to regenerate afterwards — the push is the whole publication step. Whether pushing the same version twice overwrites or is refused is a registry policy question, not something Helm enforces.
code
bash · 3 lineshelm package charts/tileserver --destination dist/
helm push dist/tileserver-2.7.14.tgz oci://registry.example.internal/platform-charts
helm show chart oci://registry.example.internal/platform-charts/tileserver --version 2.7.14go deeper
Remember the shape: package first, then push the .tgz to a base path. You never type the chart name or the version into the push destination.
Explain that name and version come from Chart.yaml inside the archive, and that a neighbouring provenance file is uploaded automatically when it exists.
Discuss publish-job design: build the archive once and push that exact file, keep credentials path-scoped, and make version immutability and retention explicit registry policy.
Decide the publication contract for the organisation — path layout, who may publish, whether charts and images share a registry, and how long a published chart must remain fetchable.
## The command and its two surprises ```bash helm package . # produces tileserver-2.7.14.tgz helm push tileserver-2.7.14.tgz oci://registry.example.internal/platform-charts ``` **Surprise one: push wants an archive.** `helm push` operates on a packaged `.tgz`. Pointing it at a chart source directory does not work; package the chart first. That is a real constraint on a pipeline, because it means the publish job has to run `helm package` (or receive the artefact from an earlier job) rather than pushing a checkout. **Surprise two: the destination stops short of the chart.** The reference you pass is the *base path*, without the chart name and without a tag. Helm opens the archive, reads `Chart.yaml`, and derives the rest: - `name: tileserver` becomes the last path segment, - `version: 2.7.14` becomes the tag. So the artefact lands at `oci://registry.example.internal/platform-charts/tileserver` tagged `2.7.14`. This is the mirror image of the consuming side, where the *full* path including the chart name is what you install. Getting the two round the wrong way is the single most common mistake: appending the chart name to the push destination publishes it at `platform-charts/tileserver/tileserver`. A useful consequence: **the filename is irrelevant.** Renaming the archive to `latest.tgz` changes nothing about where it lands, because the metadata inside the archive decides. A pipeline that constructs the destination path by string-manipulating a filename is doing work Helm already does correctly. ## The provenance file rides along Helm's provenance file is a `.prov` sitting beside the archive and named after it — `tileserver-2.7.14.tgz.prov`. If that file is present in the same directory when you push, **Helm uploads it with the chart automatically**; you do not name it on the command line and there is no flag to request it. If it is absent, nothing is uploaded and the published chart simply has no provenance for a consumer to check. Producing and verifying that file — what it contains and how a consumer checks it — is its own subject; the part that belongs to publishing is simply that the file travels with the chart when it exists, and only when it exists. ## Nothing else to do afterwards With a classic chart repository, publishing has a second half: you regenerate the repository's index and serve it, and consumers see the new version only after their next index refresh. With a registry there is no such step. The push *is* the publication, and the new tag is visible to a consumer immediately. That is genuinely simpler, and it is one of the honest arguments for registry distribution: fewer moving parts, one fewer thing to get out of sync, no static file whose staleness silently hides a release. ## Immutability is the registry's business, not Helm's Push the same `2.7.14` twice and what happens depends entirely on the registry. Some are configured to refuse a tag that already exists; others quietly move the tag to the new artefact. Helm does not arbitrate: it asks the registry to store the artefact under that tag, and the registry's policy decides. If your organisation cares that a published chart version never changes — and it should — configure that on the registry side and treat republishing a version as a policy violation rather than a routine fix. The equivalent discipline for a chart repository is exactly the same rule expressed differently. The same applies to retention. A registry may be configured to expire or clean up old tags. A `.tgz` sitting on a static file server does not disappear on its own; a tag in a registry can, if someone wrote a retention rule that did not consider charts. If a release that is still installed somewhere needs its chart to remain fetchable — for a rollback, for a rebuild, for an audit — that expectation has to be written into the registry's retention policy explicitly. ## A worked shape For a chart that ships a geospatial tile server together with a batch migration job, a publish job looks like: ```bash helm package charts/tileserver --destination dist/ ls dist/ # tileserver-2.7.14.tgz # tileserver-2.7.14.tgz.prov helm push dist/tileserver-2.7.14.tgz oci://registry.example.internal/platform-charts ``` One command, one artefact plus its provenance file, no index to regenerate, and the chart is live at `oci://registry.example.internal/platform-charts/tileserver` version `2.7.14`.
- Can you push a chart source directory instead of packaging it first?No. helm push operates on a packaged .tgz, so the pipeline has to run helm package first or take the archive from an earlier job. This is worth designing for: build the archive once, keep it as the job's artefact, and push that exact file, so the thing you tested and the thing you published are byte-for-byte the same.
- You rename the archive to tileserver-latest.tgz before pushing. Where does it land?Exactly where it would have anyway: at the path ending in the chart's name, tagged with the version from Chart.yaml inside the archive. The filename plays no part in addressing. If you want a different published version, change Chart.yaml and repackage.
- What happens if you push the same chart version twice?Helm asks the registry to store the artefact under that tag and the registry's configuration decides: some refuse an existing tag, others move it to the new content. Helm enforces nothing. Treat published versions as immutable by policy, configure the registry to back that up, and bump the version rather than republishing.
saying these in an interview costs you the question
- Tries to helm push an unpackaged chart directory
- Includes the chart name in the push destination path
- Thinks the filename determines the published name or tag
- Expects an index to be regenerated after pushing
- Believes helm push signs the chart for you
- Assumes the registry refuses to overwrite an existing tag