ArgoCD’s HelmRelease object is a more powerful way to manage Helm charts than the default Helm application type because it gives you more granular control over the Helm release lifecycle and its dependencies.

Here’s a HelmRelease in action, deploying a simple Nginx chart:

apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
  name: nginx-release
  namespace: default
spec:
  interval: 10m
  chart:
    spec:
      chart: nginx
      version: "15.x.x" # Pin to a specific version
      sourceRef:
        kind: HelmRepository
        name: ingress-nginx
        namespace: flux-system # Namespace where HelmRepository is defined
  install:
    createNamespace: true
  values:
    controller:
      replicaCount: 2
      service:
        type: LoadBalancer

This HelmRelease will:

  • Fetch the nginx chart from the ingress-nginx Helm repository.
  • Install it into the default namespace, creating the namespace if it doesn’t exist.
  • Configure Nginx with 2 replicas and a LoadBalancer service.
  • Reconcile these changes every 10 minutes.

The core problem HelmRelease solves is managing complex Helm deployments within a GitOps workflow. While ArgoCD’s native Helm support is functional, HelmRelease (originating from FluxCD, but fully integrated with ArgoCD via its Helm controller) provides a richer API for defining and managing Helm releases directly as Kubernetes custom resources. This means you can store your Helm release configurations in Git, just like your application manifests, and let ArgoCD manage their lifecycle.

Internally, ArgoCD’s Helm controller watches HelmRelease objects. When it detects a change or a new HelmRelease, it:

  1. Resolves the chart: It fetches the specified chart from its source (e.g., a Helm repository, OCI registry, or Git repository).
  2. Merges values: It combines the default chart values with any values or valuesFrom specified in the HelmRelease.
  3. Generates Helm commands: It translates these into the equivalent helm install or helm upgrade commands.
  4. Executes Helm: It runs the Helm command against your Kubernetes cluster.
  5. Monitors status: It watches the deployed Helm release and updates the HelmRelease’s status accordingly.

The HelmRepository object, referenced in the sourceRef, is crucial. It tells the Helm controller where to find the chart. Here’s a typical HelmRepository definition:

apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: HelmRepository
metadata:
  name: ingress-nginx
  namespace: flux-system
spec:
  interval: 1h
  url: https://kubernetes.github.io/ingress-nginx/

This object tells Flux/ArgoCD to periodically fetch index files from the provided URL, making charts from that repository discoverable.

You have fine-grained control over the Helm release process. For instance, the install section can specify createNamespace: true to ensure the target namespace exists before installation. The upgrade section allows for remediation strategies, defining how to handle failed upgrades. You can also use dependsOn to create explicit ordering between HelmRelease objects, ensuring that dependencies are deployed first.

# Example of ordering with dependsOn
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
  name: my-app
  namespace: default
spec:
  # ... other spec fields ...
  dependsOn:
    - name: database-release # Assumes another HelmRelease named 'database-release' exists
      namespace: default

This dependsOn field is a powerful mechanism for managing complex application stacks where certain components must be available before others. ArgoCD will ensure that database-release is successfully deployed and healthy before attempting to deploy my-app.

A common pitfall is not pinning chart versions. Always specify a version in your chart.spec. Using version: "15.x.x" is a good practice for allowing minor updates while preventing unexpected breaking changes from major version bumps. If you omit the version, Helm will fetch the latest, which can lead to unpredictable deployments and break your GitOps guarantee.

The next thing you’ll likely grapple with is managing sensitive values, like database passwords or API keys. You can’t and shouldn’t store these directly in your Git-managed HelmRelease manifest. Instead, you’ll use valuesFrom to reference Kubernetes Secret or ConfigMap objects, or even fetch values from external sources using Kustomize or other Flux/ArgoCD integrations.

Want structured learning?

Take the full Helm course →