Helmfile Cheat Sheet
Overview
Helmfile is a declarative tool for deploying and managing multiple Helm chart releases. It provides a single helmfile.yaml that defines all your Helm releases, their values, dependencies, and environments. Instead of running multiple helm install commands with various flags, Helmfile manages the entire deployment lifecycle declaratively.
Helmfile supports templating with Go templates, environment-specific value overrides, secrets management via helm-secrets, and diff-based deployment previews. It is particularly useful for managing complex Kubernetes deployments with many interdependent Helm charts across multiple environments.
Installation
# macOS
brew install helmfile
# Linux
curl -fsSL -o helmfile https://github.com/helmfile/helmfile/releases/latest/download/helmfile_linux_amd64
chmod +x helmfile
sudo mv helmfile /usr/local/bin/
# Go install
go install github.com/helmfile/helmfile@latest
# Required: helm-diff plugin
helm plugin install https://github.com/databus23/helm-diff
# Verify
helmfile version
Core Commands
| Command | Description |
|---|---|
helmfile sync | Install or upgrade all releases |
helmfile apply | Sync only releases with changes (diff first) |
helmfile diff | Show diff of pending changes |
helmfile template | Render templates locally |
helmfile lint | Lint all charts |
helmfile destroy | Delete all releases |
helmfile list | List all releases |
helmfile status | Show status of all releases |
helmfile repos | Add/update configured Helm repositories |
helmfile fetch | Fetch charts to local directory |
helmfile build | Build helmfile state (debug) |
Configuration
Basic helmfile.yaml
repositories:
- name: bitnami
url: https://charts.bitnami.com/bitnami
- name: ingress-nginx
url: https://kubernetes.github.io/ingress-nginx
releases:
- name: nginx-ingress
namespace: ingress
chart: ingress-nginx/ingress-nginx
version: 4.9.0
values:
- controller:
replicaCount: 2
- name: redis
namespace: cache
chart: bitnami/redis
version: 18.6.1
values:
- values/redis.yaml
- name: postgres
namespace: database
chart: bitnami/postgresql
version: 14.0.0
values:
- values/postgres.yaml
set:
- name: auth.postgresPassword
value: {{ requiredEnv "POSTGRES_PASSWORD" }}
Environment-Specific Configuration
environments:
dev:
values:
- env/dev/values.yaml
kubeContext: dev-cluster
staging:
values:
- env/staging/values.yaml
kubeContext: staging-cluster
production:
values:
- env/production/values.yaml
kubeContext: prod-cluster
releases:
- name: my-app
namespace: {{ .Values.namespace | default "default" }}
chart: ./charts/my-app
values:
- values/common.yaml
- values/{{ .Environment.Name }}.yaml
set:
- name: replicaCount
value: {{ .Values.replicas | default 1 }}
# Deploy to specific environment
helmfile -e dev sync
helmfile -e production apply
helmfile -e staging diff
Release Dependencies
releases:
- name: postgres
namespace: database
chart: bitnami/postgresql
version: 14.0.0
- name: redis
namespace: cache
chart: bitnami/redis
version: 18.6.1
- name: my-app
namespace: app
chart: ./charts/my-app
needs:
- database/postgres
- cache/redis
values:
- values/my-app.yaml
Values Management
Multiple Value Sources
releases:
- name: my-app
chart: ./charts/my-app
values:
# Static file
- values/base.yaml
# Environment-specific file
- values/{{ .Environment.Name }}.yaml
# Inline values
- image:
tag: {{ env "IMAGE_TAG" | default "latest" }}
config:
logLevel: {{ .Values.logLevel | default "info" }}
# Secrets (with helm-secrets plugin)
- secrets://secrets/{{ .Environment.Name }}.yaml
set:
- name: ingress.host
value: {{ .Values.domain }}
Gotmpl Values File
# values/app.yaml.gotmpl
replicaCount: {{ .Values.replicas | default 2 }}
image:
repository: {{ .Values.registry }}/my-app
tag: {{ requiredEnv "GIT_SHA" }}
ingress:
enabled: true
host: {{ .Values.domain }}
resources:
requests:
cpu: {{ .Values.cpuRequest | default "100m" }}
memory: {{ .Values.memoryRequest | default "128Mi" }}
Advanced Usage
Selectors
# Apply only specific releases
helmfile -l name=my-app apply
helmfile -l namespace=database sync
# Using labels
releases:
- name: postgres
labels:
tier: database
env: all
chart: bitnami/postgresql
- name: my-app
labels:
tier: application
env: all
chart: ./charts/my-app
helmfile -l tier=database sync
helmfile -l tier=application diff
Helmfile.d Directory
# Split into multiple files
helmfile.d/
00-repositories.yaml
10-infrastructure.yaml
20-databases.yaml
30-applications.yaml
# helmfile.d/00-repositories.yaml
repositories:
- name: bitnami
url: https://charts.bitnami.com/bitnami
# helmfile.d/20-databases.yaml
releases:
- name: postgres
chart: bitnami/postgresql
Hooks
releases:
- name: my-app
chart: ./charts/my-app
hooks:
- events: ["presync"]
showlogs: true
command: "kubectl"
args: ["apply", "-f", "k8s/namespace.yaml"]
- events: ["postsync"]
showlogs: true
command: "scripts/post-deploy.sh"
- events: ["cleanup"]
command: "kubectl"
args: ["delete", "job", "db-migration", "--ignore-not-found"]
OCI Registry Charts
repositories:
- name: my-registry
url: oci://registry.example.com/charts
oci: true
releases:
- name: my-app
chart: oci://registry.example.com/charts/my-app
version: 1.0.0
Subhelmfiles
# helmfile.yaml
helmfiles:
- path: infra/helmfile.yaml
values:
- environment: {{ .Environment.Name }}
- path: apps/helmfile.yaml
selectors:
- name=my-app
Troubleshooting
| Issue | Solution |
|---|---|
helm-diff plugin missing | Run helm plugin install https://github.com/databus23/helm-diff |
| Template rendering error | Run helmfile build to debug template output |
| Release stuck in pending | Run helm rollback <release> then retry |
| Environment variable missing | Use requiredEnv to get clear error messages |
| Chart version not found | Run helmfile repos to update repo indexes |
| Dependency cycle | Check needs: for circular references |
# Debug template rendering
helmfile build
helmfile template
# Verbose output
helmfile --debug sync
# Dry run
helmfile --dry-run apply
# Force sync even without changes
helmfile sync --force
# Show computed values
helmfile -e dev write-values
# Clean up stuck releases
helm list -A --pending
helm rollback <release-name>