Why chart storage deserves a decision
Charts start life in a git folder, and for a while that is fine. Then a second team wants to reuse one, or you need to deploy a specific older version to roll back, or an auditor asks who published what. Pointing at a branch of a git repository stops being good enough. You want immutable, versioned artefacts with access control: a chart repository.
This page covers how we choose, build and operate one as part of our GitOps, Helm, ArgoCD and Flux service. It sits directly after writing the charts and before promotion across environments.
What good looks like
- Every released chart has an immutable version number and a trace back to a commit.
- Publishing happens from CI with short-lived credentials.
- Clusters pull charts using identity, not a password pasted into a secret.
- Old versions are retained long enough for rollback and cleaned up after that.
- Nobody installs a chart from a developer’s laptop.
Choosing where charts live
| Option | Good fit when | Watch out for |
|---|---|---|
| OCI in ECR | You run on AWS and use ECR for images | Repository per chart must exist before push, naming follows the chart |
| OCI in ACR | You run on Azure | Authentication through Azure identity, tier features vary |
| GitHub Packages (OCI via ghcr.io) | Your code and pipelines are already on GitHub | Organisation permission model, package visibility defaults |
| Harbor | You want one self-hosted registry with scanning and replication | You now operate it |
| ChartMuseum | You need a classic index.yaml HTTP repository | Extra service to run, less momentum than OCI |
Our default is OCI in whichever registry you already operate. One system to secure, back up and pay for is better than two.
How it works in practice
Publishing to an OCI registry
With ECR, the flow looks like this. The chart version comes from Chart.yaml, and the push appends the chart name to the registry path:
aws ecr get-login-password --region eu-west-1 \
| helm registry login --username AWS --password-stdin \
123456789012.dkr.ecr.eu-west-1.amazonaws.com
helm package ./charts/payments-api
helm push payments-api-1.4.0.tgz \
oci://123456789012.dkr.ecr.eu-west-1.amazonaws.com/charts
Here an ECR repository named charts/payments-api must exist. We create those with Terraform so naming and lifecycle rules are consistent, and tie the setup to your infrastructure as code.
CI that releases charts
A pipeline stage lints, packages and pushes only when Chart.yaml has a new version, and fails if the version already exists. In GitHub Actions the cloud login uses OIDC federation, so there are no stored access keys. The general pattern, and why it matters, is covered in our CI/CD best practices guide and under CI/CD pipeline services.
Consuming charts from the cluster
ArgoCD references the chart and an exact version in the Application source. Flux defines a HelmRepository with type: oci and a HelmRelease that pins the version:
apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
metadata:
name: internal-charts
namespace: flux-system
spec:
type: oci
interval: 10m
url: oci://123456789012.dkr.ecr.eu-west-1.amazonaws.com/charts
provider: aws
Setting the provider to a cloud name lets Flux use the node or workload identity rather than a static secret. ArgoCD can obtain short-lived registry tokens too, though it commonly needs a small refresh mechanism for ECR because tokens expire after hours. We build that in and test it, since expired registry credentials are a classic cause of mysterious sync failures.
Governance and safety
Immutability and retention
Enable tag immutability on the registry so a published version can never be overwritten. A chart that changes under the same version is the single most confusing failure in Helm operations. Add lifecycle rules to keep a defined number of recent versions and everything referenced by a live environment.
Scanning and provenance
Rendered charts often reference images and sometimes bundle dependencies. We scan images in the pipeline and flag outdated chart dependencies. Where you need provenance, Cosign signs the OCI artefact and the cluster verifies it using an admission policy. This adds operational weight, so we recommend it for regulated environments or when third parties consume your charts.
Access control
Separate who can publish from who can pull. CI gets push rights to specific repositories; clusters get pull only; humans get read access for debugging. This lines up with the GitOps RBAC model.
Decisions and trade-offs
Chart in the application repository or its own. Keeping the chart with the code makes versioning together simple but couples release cycles. A shared library chart in its own repository suits many services. We pick per service shape.
Monorepo of charts versus one per chart. A single repository with chart-testing’s change detection works well up to a few dozen charts.
When not to bother. If one team deploys three internal charts to one cluster, git references pinned to a tag can work temporarily. Move to a registry when a second consumer or an audit requirement appears.
A worked example: releasing version 1.5.0
A developer changes the chart, bumps version in Chart.yaml to 1.5.0 and opens a pull request. CI lints and packages it, then runs a template check against a few values files. On merge, the pipeline pushes the package to the registry and tags the commit. A bot opens a pull request in the GitOps repository that moves staging to 1.5.0, and promotion continues from there. Nobody ran helm push by hand, and the registry shows exactly which pipeline produced each version.
Common failure modes
- Overwritten versions. Fixed with immutability.
- Expired registry tokens. Fixed with identity-based auth or scheduled refresh, and an alert.
- Version bumps forgotten. CI blocks merges that change a chart without bumping its version.
- Public by accident. Package visibility is verified in the setup and reviewed.
- Floating dependencies. Chart dependencies use exact versions and a committed lock file.
Delivery and handover
The registry, naming scheme, publishing pipeline and cluster access are delivered as code in your repositories. A runbook covers releasing a chart, rolling back, rotating credentials and deleting versions safely. Your engineers publish a chart themselves before we hand it over.
How to tell it is working
Every deployed chart version can be traced to a pipeline run and a commit. Rollback is a one-line version change in git. Registry credential failures are rare, and when they occur an alert names them. If you want a second opinion on your setup, book a consultation.