Skip to content

Helmfile declaratively manages multiple Helm releases across environments. Instead of running helm install commands manually or writing wrapper scripts, you define all your Helm charts, values, and environments in a single helmfile.yaml — then sync them all with one command.

1. Install & Basic Structure

Install Helmfile and understand the core config file
# Install:
brew install helmfile      # macOS
# Or: https://github.com/helmfile/helmfile/releases (single binary)

# helmfile.yaml — basic structure:
repositories:
  - name: stable
    url: https://charts.helm.sh/stable
  - name: bitnami
    url: https://charts.bitnami.com/bitnami

releases:
  - name: nginx-ingress
    chart: ingress-nginx/ingress-nginx
    version: 4.9.0
    namespace: ingress-nginx
    createNamespace: true
    values:
      - controller.replicaCount: 2
        controller.service.type: LoadBalancer

  - name: cert-manager
    chart: jetstack/cert-manager
    version: v1.14.0
    namespace: cert-manager
    createNamespace: true
    set:
      - name: installCRDs
        value: true

  - name: my-app
    chart: ./charts/my-app          # local chart
    namespace: production
    values:
      - values/production.yaml      # values file (relative to helmfile.yaml)

# Core commands:
helmfile sync        # install/upgrade all releases to match helmfile.yaml
helmfile apply       # like sync but diffs first (safer in CI)
helmfile diff        # show what would change (no changes applied)
helmfile destroy     # uninstall all releases
helmfile list        # list all releases + status
helmfile status      # detailed status per release

2. Environments

Different config for dev, staging, and production
# helmfile.yaml with environments:
environments:
  default:
    values:
      - values/common.yaml
  staging:
    values:
      - values/common.yaml
      - values/staging.yaml
  production:
    values:
      - values/common.yaml
      - values/production.yaml
    secrets:
      - secrets/production.yaml.dec   # decrypted by helm-secrets

releases:
  - name: my-app
    chart: ./charts/my-app
    namespace: "{{ .Values.namespace }}"   # from environment values
    values:
      - replicaCount: "{{ .Values.replicaCount }}"
        image.tag: "{{ .Values.imageTag }}"

# values/staging.yaml:
namespace: staging
replicaCount: 1
imageTag: staging-latest

# values/production.yaml:
namespace: production
replicaCount: 3
imageTag: v1.4.2

# Deploy to specific environment:
helmfile --environment production sync
helmfile --environment staging diff

# Environment-conditional releases (only deploy monitoring in production):
releases:
  - name: prometheus-stack
    chart: prometheus-community/kube-prometheus-stack
    condition: monitoring.enabled    # enabled/disabled via environment values

3. Selectors & Targeting

Deploy only specific releases from a large helmfile
# Label releases for selective targeting:
releases:
  - name: nginx-ingress
    chart: ingress-nginx/ingress-nginx
    labels:
      tier: infrastructure
      app: ingress

  - name: my-app
    chart: ./charts/my-app
    labels:
      tier: application
      team: backend

  - name: monitoring
    chart: prometheus-community/kube-prometheus-stack
    labels:
      tier: monitoring

# Deploy only application tier:
helmfile --selector tier=application sync

# Deploy only a specific release:
helmfile --selector name=my-app sync
helmfile --selector name=my-app diff

# Deploy multiple labels (AND condition):
helmfile --selector tier=application,team=backend sync

# Useful for:
# - Deploying infrastructure separately from applications
# - Updating only the changed service in a large cluster
# - Running diff on specific releases in CI

4. Secrets with helm-secrets

Encrypt secrets in helmfile.yaml using SOPS or Vault
# Install helm-secrets plugin:
helm plugin install https://github.com/jkroepke/helm-secrets

# Encrypt a values file with SOPS + age key:
sops --age $(cat age-key.pub) --encrypt values/secrets.yaml > values/secrets.enc.yaml

# Reference encrypted file in helmfile:
releases:
  - name: my-app
    chart: ./charts/my-app
    secrets:
      - values/secrets.enc.yaml      # helmfile auto-decrypts via helm-secrets

# .sops.yaml (encryption rules):
creation_rules:
  - path_regex: secrets/.*\.enc\.yaml
    age: age1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

# Environment-level secrets:
environments:
  production:
    secrets:
      - secrets/production.enc.yaml   # decrypted before rendering

# Vault as secret backend:
# helm secrets vault decrypt values/secrets.yaml
# Reference vault paths in values:
# db_password: "ref+vault://secret/production/myapp#db_password"

5. Hooks & Advanced Patterns

Pre/post hooks, needs ordering, and chart dependencies
# needs: deploy releases in dependency order
releases:
  - name: cert-manager
    chart: jetstack/cert-manager
    needs:
      - ingress-nginx              # wait for ingress to be ready first

  - name: ingress-nginx
    chart: ingress-nginx/ingress-nginx

  - name: my-app
    chart: ./charts/my-app
    needs:
      - cert-manager               # wait for cert-manager CRDs

# Hooks (run kubectl or helm commands before/after release):
releases:
  - name: my-app
    chart: ./charts/my-app
    hooks:
      - events: [presync]
        command: kubectl
        args: [apply, -f, crds/]   # apply CRDs before installing chart
      - events: [postsync]
        command: kubectl
        args: [rollout, status, deployment/my-app, -n, production]

# Template rendering (Go templates in helmfile.yaml):
releases:
  - name: my-app
    chart: ./charts/my-app
    set:
      - name: gitSHA
        value: {{ exec "git" (list "rev-parse" "--short" "HEAD") | trim }}

# CI/CD usage:
# helmfile diff --detailed-exitcode   # exit 1 if diff exists (use for PR checks)
# helmfile apply                       # apply only changed releases
# helmfile test                        # run helm test on all releases

Track Helmfile, Helm, and Kubernetes tooling releases. ReleaseRun monitors Kubernetes, Docker, and 13+ DevOps technologies.

Related: Kubernetes YAML Reference | Kustomize Reference | ArgoCD Reference

🔍 Free tool: K8s YAML Security Linter — after helmfile template, paste the rendered output here to check 12 K8s security misconfigurations.