Helmfile Reference: Multi-Helm Release Management, Environments, Secrets & Hooks
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.
Founded
2023 in London, UK
Contact
hello@releaserun.com