A HelmRelease in Flux is not just a declarative way to manage Helm charts; it’s a sophisticated reconciliation loop that actively monitors and enforces your desired Kubernetes state against what’s actually deployed.

Let’s see it in action. Imagine you have a redis Helm chart you want to deploy.

apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
  name: my-redis
  namespace: default
spec:
  interval: 5m
  chart:
    spec:
      chart: redis
      version: "16.x.x" # Specify a version for stability
      sourceRef:
        kind: HelmRepository
        name: bitnami
        namespace: flux-system # Namespace where HelmRepository is defined
  values:
    architecture: standalone
    replicaCount: 1
    auth:
      enabled: false

When Flux reconciles this HelmRelease, it doesn’t just apply a Helm chart once. It continuously checks:

  1. Chart Source: Is the specified chart (redis) at the exact version (16.x.x) available in the bitnami Helm repository?
  2. Configuration: Do the deployed Redis pods match the values specified (e.g., architecture: standalone, replicaCount: 1, auth: enabled: false)?
  3. Helm Release Status: Is the Helm release created by this HelmRelease in a deployed state?

If any of these drift (e.g., someone manually scales down the Redis pods, or a new minor version of redis is released and Flux picks it up if version is not pinned), Flux will automatically revert it to the desired state defined in your HelmRelease manifest.

The core problem HelmRelease solves is the drift between your declared infrastructure state and the actual running state in your Kubernetes cluster, especially for applications managed by Helm. It brings GitOps principles to Helm deployments by treating Helm releases as first-class Kubernetes resources managed by a declarative API and an automated reconciliation engine.

Internally, Flux uses the Helm controller, which watches for HelmRelease objects. When it sees one, it:

  • Fetches the Chart: It pulls the specified chart from the configured HelmRepository (or other sources like Git repositories).
  • Merges Values: It combines default chart values, values from the HelmRelease’s values field, and potentially values from a valuesFrom field (pointing to ConfigMaps or Secrets).
  • Installs/Upgrades Helm Release: It then uses Helm commands (helm install or helm upgrade) to apply the merged configuration to your cluster.
  • Monitors Status: Crucially, it continuously monitors the Helm release’s status and the Kubernetes resources it manages (Deployments, StatefulSets, Services, etc.). If a discrepancy is detected, it triggers another Helm upgrade to enforce the desired state.
  • Handles Rollbacks: If an upgrade fails, Flux can be configured to automatically roll back to the previous stable release.

The interval field dictates how often the Helm controller checks for drifts and attempts to reconcile the HelmRelease. For production, you’ll want to balance responsiveness with resource usage. 5m is a common starting point, but for critical applications, you might consider 1m or even 30s. Conversely, for less critical applications, 15m or 30m might suffice.

The timeout field in the HelmRelease spec is often overlooked but is critical for production. It specifies how long the Helm controller should wait for a Helm operation (like install or upgrade) to complete before timing out. A common mistake is to leave this at the Helm default (10 minutes), which might be too long for fast-paced environments or too short for complex deployments. For most production scenarios, setting this to a value like 15m or 30m provides a reasonable window for complex application deployments while preventing indefinite hangs.

apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
  name: my-redis
  namespace: default
spec:
  interval: 5m
  timeout: 15m # Explicitly set a reasonable timeout
  chart:
    spec:
      chart: redis
      version: "16.x.x"
      sourceRef:
        kind: HelmRepository
        name: bitnami
        namespace: flux-system
  values:
    architecture: standalone
    replicaCount: 1
    auth:
      enabled: false

A subtle but powerful feature is the postRenderers field. This allows you to apply arbitrary transformations to the Helm manifest after it’s rendered but before it’s applied to the cluster. This is incredibly useful for injecting sidecars, mutating labels, or applying common security policies across multiple HelmRelease objects without modifying the base chart. For instance, you could use a kustomize patch or a sed command within a postRenderer to add an annotation to every deployment managed by a HelmRelease.

The next step after mastering HelmRelease is understanding how to manage complex dependencies between multiple HelmRelease objects using dependsOn or by leveraging Flux’s Kustomization to orchestrate multiple HelmRelease resources.

Want structured learning?

Take the full Flux course →