Helm packages and templates your Kubernetes manifests. Argo CD watches a source, renders it and keeps the cluster matching it. Used together, you describe a chart, a version and a set of values in an Argo CD Application, and Argo CD does the rendering, applying and drift detection. The catch is that Argo CD does not run helm install, so a few Helm habits stop working. This guide covers how the pairing works, how to write the Application, how to handle values and environments, and what to check when something looks wrong.
TL;DR
- Argo CD renders charts with
helm templateand applies the output itself. The app is tracked as an Argo CD Application, not as a Helm release. - Point
spec.sourceat a Helm repository, an OCI registry or a Git path, pin the chart version intargetRevision, and set values withvaluesObject,valueFilesorparameters. - For several environments, keep one chart and one values file per environment in Git, and generate Applications with an ApplicationSet or App of Apps.
- Expect
helm lsto come back empty, Helm hooks to be mapped onto Argo CD hooks, and private chart repositories to need registering first.
Table of Contents
- How Helm and Argo CD fit together
- Three ways to source a chart
- Writing the Application manifest
- Values, parameters and precedence
- Managing several environments
- Sync behavior: updates, rollbacks and drift
- Helm hooks and Argo CD hooks
- Private repositories and common problems
- Perspective: what we see in the day-to-day
- Watching Helm and Argo CD work from one window
- A short checklist before your first production sync
- FAQ
- Sources
How Helm and Argo CD fit together
The two tools do different jobs. Helm is the packaging and templating layer: a chart plus values produces manifests. Argo CD is the GitOps controller: it compares what is declared with what runs and reconciles the difference. Argo CD's Helm documentation states it plainly: Argo CD uses Helm to inflate charts with helm template, and Argo CD handles the application's lifecycle.
That design has practical consequences:
- No Helm release object. The chart is turned into raw manifests that Argo CD applies, so the application is tracked as an Argo CD resource rather than a standard Helm release. Red Hat's write-up on Helm and Argo CD notes the visible effect:
helm lswill not list charts that Argo CD manages. - Git is the control point. Chart version, values and target namespace live in a manifest you can review and revert.
- Drift is visible. Argo CD keeps comparing the live state with the rendered desired state, and with automated sync it can correct differences.
If you come from helm upgrade --install in a pipeline, the mental shift is this: you no longer push a release. You change a declaration and let the controller converge.
Three ways to source a chart
Argo CD can read Helm charts from three kinds of places. Red Hat's overview of three patterns describes the split: a chart in a Git repository (URL and path), or a chart from a remote Helm repository (chart name, repository URL and target revision).
| Source | What you set in spec.source | Best for |
|---|---|---|
| Helm repository | repoURL, chart, targetRevision | Third-party charts such as ingress controllers or monitoring stacks |
| OCI registry | repoURL (no oci:// prefix), chart, targetRevision | Charts your team publishes to a container registry |
| Git repository | repoURL, path, targetRevision (branch, tag or commit) | Charts you own and change alongside the app |
For public OCI registries, the Argo CD docs say to give the repository URL without the oci:// prefix. A Git-hosted chart is the simplest way to start: the chart and its values move through the same pull request.
Writing the Application manifest
An Application can be created in the UI, with the CLI, or by applying YAML. The YAML is the one worth keeping, because you can commit it. Here is an Application that installs a chart from a Helm repository:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: ingress-nginx
namespace: argocd
spec:
project: default
source:
repoURL: https://kubernetes.github.io/ingress-nginx
chart: ingress-nginx
targetRevision: 4.11.3
helm:
releaseName: ingress-nginx
valuesObject:
controller:
replicaCount: 2
destination:
server: https://kubernetes.default.svc
namespace: ingress-nginx
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
The version number above is only an example of the format. Pick the chart version you have tested.
A few points about this manifest:
targetRevisionholds the chart version for Helm and OCI sources. Pin an exact version. A floating range means a chart upstream can change what lands in production without a commit on your side.destination.serveris the cluster the resources go to. The in-cluster address means the cluster Argo CD itself runs in. For remote clusters you register them with Argo CD first.automatedwithpruneandselfHealturns on the drift correction. Leaveautomatedout while you are learning and sync manually.releaseNamematters because templates often use.Release.Name. Set it deliberately and do not change it later, or resource names change with it.
After you create the Application, expect it to show OutOfSync at first. After a sync, it moves to Synced and Healthy, as KodeKloud's walkthrough shows. To see exactly what Helm produced, open the app in the UI and check App Details, then Manifests.
Values, parameters and precedence
The values you give a chart can arrive in several ways, and the Argo CD docs define a strict order of precedence among them. The main inputs:
valueFiles: paths to values files in the source repository. Good for per-environment files.valuesObject: values written inline as YAML in the Application. Convenient for a few overrides, harder to read when it grows.parameters: single--setstyle overrides. On the CLI the equivalent is the--helm-setflag when you create the Application.
A workable rule: keep everything environment-wide in valueFiles, and use parameters only for values a pipeline needs to inject, such as an image tag. Mixing all three for the same key makes it hard to tell where a value came from. When in doubt, check the rendered manifest in the UI rather than guessing which input won.
Argo CD also supports value hierarchies, where several files layer from general to specific. Its multi-source feature lets you keep the chart in one repository and the values in another, which suits third-party charts. Akuity's guide to Helm hierarchies in multi-source Applications walks through that layout, including ApplicationSets.
Managing several environments
Once one Application works, the question becomes how to avoid copying it for dev, staging and production. Two patterns cover most teams.
One chart, one values file per environment
Keep a single chart and a folder of values files:
my-app/
chart/
values/
dev.yaml
staging.yaml
prod.yaml
Each environment's Application points at the same chart and a different valueFiles entry. Because chart versions are set in targetRevision, dev can run a newer chart than prod and you promote by changing one line. Red Hat's patterns article describes this same idea of environment-specific charts or versions in Git.
ApplicationSet or App of Apps
Writing a dozen near-identical Applications by hand is where mistakes creep in. Two ways to avoid it:
- ApplicationSet generates Applications from a template plus a list, a directory layout or a cluster list. One template, many environments or clusters.
- App of Apps is a parent Application whose source is a folder of Application manifests. Declarative manifests stored in Git let Argo CD manage its own application definitions, as the Argo CD application creation guide describes.
A useful split: ApplicationSets for repeated shapes (the same app on many clusters), App of Apps for bootstrapping a cluster with a hand-curated set of platform components.
If your environments are separate clusters, you also need a safe way to give Argo CD access to them. We wrote about that in Argo CD across clusters without static tokens.
Sync behavior: updates, rollbacks and drift
When a chart version or its parameters change in the source, Argo CD detects the change and can redeploy it according to the sync policy, as Octopus Deploy's explainer puts it. With manual sync, the Application shows OutOfSync and waits for you. With automated sync, it applies the change.
Some habits that keep this calm:
- Review the diff before syncing. The diff shows rendered manifests, not chart values, so it catches template changes you did not expect when bumping a chart version.
- Treat Git as the rollback source. Argo CD supports rollback in the UI and CLI, but with automated sync a rollback in the UI can be undone by the next reconcile. Reverting the commit is the durable fix.
- Do not edit live resources. With
selfHealon, manualkubectl editchanges are reverted. With it off, they show as drift. Either way, the change belongs in Git.
Helm hooks and Argo CD hooks
Helm hooks are normal resources annotated with helm.sh/hook. Because Argo CD never runs helm install or helm upgrade, it handles them differently: the Argo CD Helm guide says it supports many Helm hooks by mapping the annotations onto its own hook annotations. It also warns that this is annotation compatibility, not a guarantee that lifecycle behavior is identical.
In practice:
- Install and upgrade hooks both map to the same sync phase, because Argo CD does not tell a first install apart from a later sync the way Helm does.
- A database migration Job that ran as a
pre-upgradehook will run before every sync, so make it idempotent. - For ordering regular resources, use Argo CD sync waves rather than relying on hook weights. For anything critical, test the chart in a non-production Application before trusting the mapping.
Private repositories and common problems
Most failed first deployments come from a short list of causes.
The repository is not registered. Private Helm and OCI repositories must be registered in Argo CD's settings before an Application can pull from them. Octopus Deploy's tutorial makes the same point for restricted environments. Argo CD's private repositories documentation shows both the CLI route (argocd repo add with --type helm and --enable-oci for OCI) and a declarative Secret labeled argocd.argoproj.io/secret-type: repository. The declarative Secret is the better choice if you want the setup reproducible.
helm ls shows nothing. This is expected, as covered above. Use kubectl or the Argo CD UI to see what is deployed, and look at the Application's resource tree.
The Application is OutOfSync forever. Usually a controller or webhook mutates a field that the chart also sets. Look at the diff for the field in question, then use ignoreDifferences for that specific path instead of disabling sync.
Values do not seem to apply. Check the rendered manifests in the UI, then check which of valueFiles, valuesObject and parameters sets the key.
Security. Pin chart versions, keep credentials in Secrets rather than in values files committed to Git, and scope each Application to an Argo CD Project that limits which repositories and namespaces it may touch. Review upstream chart changes in the rendered diff before bumping a version, since a chart is code that creates cluster resources.

Perspective: what we see in the day-to-day
Argo CD is excellent at declaring and reconciling. It is less comfortable when you need to look at what is happening right now: which pod is crash-looping, what its logs say, whether the new ReplicaSet ever became ready. The UI can show that, but teams that run many clusters end up juggling Argo CD tabs, kubectl contexts and a separate Helm client.
We build Kubezilla Desktop around that gap. Git and Argo CD stay the source of truth for what should run. A native desktop app is where you go to inspect, tail logs and open a pod terminal across clusters, with kubeconfigs stored locally, no cloud sync and no telemetry. Our rule of thumb for Helm with Argo CD is simple: change things in Git, observe them everywhere else, and keep the number of places you need credentials for as small as you can.
— Margus
Watching Helm and Argo CD work from one window
Kubezilla Desktop is a native app for Linux, macOS and Windows, built in Rust to stay light on RAM and fast to start. It gives you a single interface for your clusters, with live log streaming, metrics, pod terminals, YAML editing and workload scaling, plus Helm and Argo CD operations when you need them. It connects to multiple clusters, including remote ones through SSH tunnels, so you can skip VPN and bastion juggling. It costs €5 per month, and you can see the details on the Kubezilla Desktop pricing page.

If you manage more than one cluster, see how the Kubernetes desktop app fits next to your GitOps setup. Two related guides: kubeconfig context management for keeping contexts straight, and Kubernetes dry runs for checking a change before it lands.
A short checklist before your first production sync
- Pin
targetRevisionto an exact chart version you have tested. - Put values in files in Git, one per environment, and use
parametersonly for injected values like image tags. - Register private repositories declaratively.
- Start with manual sync; turn on
automatedwithpruneandselfHealonce the diff is clean for a few syncs. - Review the rendered Manifests view after every chart version bump.
- Make hook Jobs idempotent, and test hook behavior in a non-production Application.
- Assign each Application to a Project with restricted sources and destinations.
FAQ
Does Argo CD use Helm to install charts?
Only for rendering. Argo CD runs helm template to produce manifests and then applies them itself, so no Helm release is created. Lifecycle, sync and rollback are handled by Argo CD.
Why doesn't helm ls show my Argo CD application?
Because the chart was never installed as a Helm release. Argo CD tracks it as an Application resource instead. Use the Argo CD UI, the argocd app commands or kubectl to see what is deployed.
Where do I set the chart version?
In spec.source.targetRevision of the Application. For a Git source it is a branch, tag or commit instead. Pin an exact chart version for production so upgrades are always a reviewed commit.
How do I override Helm values in Argo CD?
Use valueFiles for files in the repository, valuesObject for inline YAML, or parameters for single overrides. From the CLI, the --helm-set flag does the latter when creating an Application. Check the rendered manifests in the UI to confirm what was applied.
Can I use a private chart repository?
Yes. Register the repository in Argo CD first, either with argocd repo add or with a declarative Secret, and add credentials there. Then reference it from the Application's repoURL.
Sources
- Helm, Argo CD user guide
- Private Repositories, Argo CD documentation
- Continuous Delivery with Helm and Argo CD, Red Hat
- 3 patterns for deploying Helm charts with Argo CD, Red Hat Developer
- Deploy apps using Helm Chart, KodeKloud
- Argo CD with Helm charts, Octopus Deploy
