Helmfile
Helmfile is a declarative specification for deploying Helm charts across multiple environments with flexible configuration management.
Overview
Helmfile allows you to:
- Define releases, environments, and values in a single
helmfile.yaml - Manage multiple environments (dev, staging, prod)
- Share common configuration across releases
- Use Go templating for dynamic values
- Integrate with GitOps workflows
Installation
# Binary installation
brew install helmfile
# Helm plugin
helm plugin install https://github.com/helmfile/helmfile
# From source
go install github.com/helmfile/helmfile@latestBasic Structure
# helmfile.yaml
repositories:
- name: bitnami
url: https://charts.bitnami.com
- name: prometheus-community
url: https://prometheus-community.github.io/helm-charts
environments:
dev:
values:
- environments/dev.yaml
staging:
values:
- environments/staging.yaml
prod:
values:
- environments/prod.yaml
releases:
- name: myapp
chart: ./charts/myapp
namespace: {{ .Environment.Name }}
values:
- values/{{ .Environment.Name }}.yaml
secrets:
- secrets/{{ .Environment.Name }}.yaml.gpg
installed: {{ .Environment.Name != "dev" || .Values.installMyapp }}Environment Configuration
Basic Environment
# helmfile.yaml
environments:
dev:
values:
- path: environments/dev/values.yaml
# Can include multiple files
- path: environments/dev/secrets.yaml.enc
encrypted: true
staging:
values:
- environments/staging/values.yaml
prod:
values:
- environments/prod/values.yamlEnvironment with Overrides
environments:
prod:
values:
- replicas: 5
- image.tag: v1.2.3
- environment: production
secrets:
- path: environments/prod/secrets.yaml
Encrypted: trueReleases Configuration
Basic Release
releases:
- name: myapp
chart: ./charts/myapp
namespace: myapp
values:
- values/common.yaml
- values/{{ .Environment.Name }}.yaml
set:
- name: image.tag
value: latestRelease with Version
releases:
- name: redis
chart: bitnami/redis
version: 18.x.x
namespace: cache
values:
- values/redis.yaml
installed: {{ .Environment.Name != "dev" }}Conditional Release
releases:
- name: monitoring
chart: prometheus-community/prometheus
installed: {{ .Values.enableMonitoring }}
namespace: monitoring
values:
- values/monitoring.yamlValues Management
Layered Values
releases:
- name: myapp
chart: ./charts/myapp
values:
# Base values (always applied)
- values/base.yaml
# Environment-specific (takes precedence)
- values/{{ .Environment.Name }}.yaml
# Environment-local overrides
- path: values/{{ .Environment.Name }}/local.yaml
optional: trueGo Templating in Values
releases:
- name: myapp
chart: ./charts/myapp
values:
- image:
repository: {{ requiredEnv "IMAGE_REPO" }}
tag: {{ .Environment.Name | toYaml | quote }}
replicaCount: {{ .Values.defaultReplicas | default 2 }}Environment-Specific Secrets
releases:
- name: myapp
chart: ./charts/myapp
secrets:
- path: secrets/{{ .Environment.Name }}/db-creds.yaml
Encrypted: true # helm-secrets requiredMultiple Environments
Directory Structure
├── helmfile.yaml
├── environments/
│ ├── base.yaml # Shared values
│ ├── dev/
│ │ └── values.yaml
│ ├── staging/
│ │ └── values.yaml
│ └── prod/
│ └── values.yaml
├── charts/
│ └── myapp/
│ └── ...
└── secrets/
├── dev/
│ └── secrets.yaml.enc
├── staging/
│ └── secrets.yaml.enc
└── prod/
└── secrets.yaml.enc
Environment Inheritance
# helmfile.yaml
environments:
dev:
values:
- base.yaml
- environments/dev.yaml
staging:
values:
- base.yaml
- environments/staging.yaml
prod:
values:
- base.yaml
- environments/prod.yamlMulti-Cluster Deployments
Cluster Contexts
# helmfile.yaml
environments:
dev-us:
context: dev-us-cluster
values:
- clusters/dev-us.yaml
prod-us:
context: prod-us-cluster
values:
- clusters/prod-us.yaml
prod-eu:
context: prod-eu-cluster
values:
- clusters/prod-eu.yaml
releases:
- name: myapp
chart: ./charts/myapp
namespaces:
- myapp
values:
- environments/shared.yaml
installed: true
# Deploy to specific clusters
environments:
- dev-us
- prod-us
- prod-euKustomize Integration
releases:
- name: myapp
chart: ./charts/myapp
postRenderers:
- kind: kustomize
path: ./overlays/{{ .Environment.Name }}Helmfile Commands
Apply to Environment
# Apply to default environment
helmfile apply
# Apply to specific environment
helmfile -e prod apply
# Apply with diff
helmfile -e prod diff
# Apply with cleanup (remove resources)
helmfile -e prod destroySync and Update
# Sync all releases
helmfile sync
# Sync specific release
helmfile -e prod sync myapp
# Update dependencies
helmfile deps
# List releases
helmfile listTemplate and Debug
# Render templates
helmfile template
# Debug output
helmfile -e prod diff --debug
# Lint
helmfile lintAdvanced Configuration
Labels and Selectors
releases:
- name: frontend
labels:
component: web
tier: frontend
chart: ./charts/frontend
- name: backend
labels:
component: api
tier: backend
chart: ./charts/backend
# Use label selectors
helmfile -l tier=frontend syncTemplates (Helmfile Templates)
# _helpers.tpl (in same directory as helmfile.yaml)
{{- define "myapp.common" -}}
replicas: {{ .Values.myapp.replicas | default 2 }}
image:
repository: myapp
tag: {{ .Values.imageTag | default "latest" }}
{{- end -}}
# In helmfile.yaml
releases:
- name: myapp
chart: ./charts/myapp
values:
- inline: |
{{ template "myapp.common" . }}Environment Variables
# Set environment variable
export ENVIRONMENT=prod
helmfile apply
# Or inline
ENVIRONMENT=prod helmfile applyIntegration with ArgoCD
# ArgoCD Application for Helmfile
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: myapp-helmfile
spec:
source:
repoURL: https://github.com/org/repo.git
path: .
targetRevision: main
plugin:
name: helmfile
parameters:
- name: environment
value: prodBest Practices
1. Use Version Control
# All helmfile configs in Git
git add helmfile.yaml environments/
git commit -m "Update helmfile for prod"
git push2. Separate Secrets
# helmfile.yaml
releases:
- name: myapp
secrets:
- path: secrets/{{ .Environment.Name }}/secrets.yaml.enc
Encrypted: true3. Use Environment Inheritance
# environments/base.yaml
common:
imagePullPolicy: IfNotPresent
resources:
limits:
cpu: 500m
memory: 512Mi
# environments/prod.yaml
{{- load "environments/base.yaml" | toYaml | nindent 0 }}
replicas: 54. Test Before Production
# Dry-run in dev first
helmfile -e dev diff
# Apply to dev
helmfile -e dev apply
# Verify in dev
helmfile -e dev list
# Then promote to prod
helmfile -e prod diff
helmfile -e prod applyCommon Patterns
Atomic Deployments
releases:
- name: myapp
chart: ./charts/myapp
atomic: true # Rollback on failure
timeout: 5m
wait: true
cleanupOnFail: truePre/Post Hooks
releases:
- name: myapp
chart: ./charts/myapp
hooks:
- events: ["prepare", "pre-upgrade"]
command: /bin/sh
args: ["-c", "echo preparing release"]GitOps Automation
# In CI/CD
helmfile -e prod apply --interactive=false
# Or with auto-approve
helmfile -e prod apply --auto-approveTroubleshooting
Debug Template Rendering
# Template locally
helmfile template
# Show diff
helmfile diff
# Verbose output
helmfile -e prod apply --debugCommon Issues
| Issue | Solution |
|---|---|
helmfile: command not found | Install helmfile binary |
multiple repositories with same name | Check for duplicate entries |
environment not found | Check environments section |
release not found | Verify release name in releases |
Reset Environment
# Clean up releases
helmfile -e prod destroy
# Remove lock file
rm helmfile.lock
# Re-apply
helmfile -e prod apply