* fix: resolve OCI version constraints before deriving the shared chart cache path When an OCI release uses a semver constraint (e.g. `~1`, `^2.0.0`, `*`), `getOCIChartPath` currently derives the on-disk cache directory from the raw constraint string via `safeVersionPath`, which substitutes constraint characters (`~`, `^`, `>`, `<`, `!`, `|`, `=`, ` `, `,`, `*`) with `_`. So `version: ~1` becomes `.../mychart/_1/` on disk. `acquireChartLock` then refuses to refresh anything under the shared cache dir to avoid race conditions between concurrent processes, so once the constraint is first resolved and written to `_1/`, every subsequent render on that machine (or that container replica) returns the pinned tarball regardless of newer matching tags being published. In multi-pod deployments like ArgoCD's argocd-repo-server this shows up as intermittent stale renders: different pods populate their caches at different moments and serve different snapshots of the same `~1` release forever. Fix: for OCI releases whose `version` looks like a constraint, run `helm show chart <ref> --version <constraint> [flags]` and use the returned metadata.Version as the effective version for all downstream cache-key and path derivation. Helm already resolves the constraint against the registry and returns the concrete matching Chart.yaml. Callers get a content-addressable cache path (`.../mychart/1.0.1/`) that naturally invalidates when the constraint resolves to a new version. Exact-version releases and non-OCI releases skip the extra call. Adds an opt-out `resolveOCIVersions` field on `helmDefaults` and `ReleaseSpec` (both default true). If the resolution call fails transiently, the resolver logs a warning and falls back to the pre-fix behavior so a network hiccup doesn't break rendering. Adds `ShowChartWithFlags` to helmexec.Interface so the existing `ShowChart` API stays backwards compatible. Resolves #2766 Signed-off-by: Samuel Archambault <samuel.archambault@getmaintainx.com> * refactor: move ShowChartWithFlags to a ChartInspector capability interface Address Copilot review feedback on PR #2768: adding a method to the exported helmexec.Interface is a source-breaking change for every third-party implementation and mock of that interface, even though ShowChart itself stayed backward-compatible. Move ShowChartWithFlags off Interface and onto a new capability interface, helmexec.ChartInspector, following the same pattern used by the existing DependencyUpdater capability interface. The concrete execer and the exectest.Helm test stub still satisfy it (they already have the method); the OCI resolver in state.HelmState now type-asserts and falls back to the pre-fix caching behavior when the capability is absent, so downstream callers with their own helmexec.Interface implementations keep compiling untouched. Adds TestResolveOCIConstraintVersion_ChartInspectorFallback that exercises the type-assertion path with a helm value that satisfies Interface but deliberately does not satisfy ChartInspector. Reverts ShowChartWithFlags additions from testutil.noCallHelmExec and app_test.mockHelmExec since Interface no longer requires them. Signed-off-by: Samuel Archambault <samuel.archambault@getmaintainx.com> * fix: detect wildcard-segment semver constraints (1.x, 1.X) as constraints Address Copilot review feedback on PR #2768: the previous isVersionConstraint implementation scanned the input for operator characters (~, ^, >, <, !, |, =, space, comma, *). Masterminds/semver also accepts wildcard-segment constraints like "1.x", "1.X", "1.x.x", and "1.2.X" that contain no operator characters. Those would slip past the classifier, bypass OCI constraint resolution, and remain cached forever under the raw ".../mychart/1.x/" path — the same stale-cache bug the PR is meant to fix. Replace the character scan with a semver-parser-based check: a value is a constraint iff Masterminds/semver rejects it as a NewVersion but accepts it as a NewConstraint. This correctly: - Recognizes wildcard forms (1.x, 1.X, 1.x.x, 1.2.x, v1.x). - Preserves exact versions where "x" appears in prerelease metadata ("1.0.0-alpha.x") or build metadata ("1.0.0+x", "1.0.0+build.x.1") without misclassifying them, which a naive "add x to the scanned charset" fix would have gotten wrong. - Continues to classify values that are neither a version nor a constraint (empty string, "latest", junk) as non-constraints; helm handles those elsewhere. Removes the now-unused versionConstraintChars string constant. Expands TestIsVersionConstraint with 8 wildcard cases and 3 prerelease /build metadata cases containing "x", plus 2 non-parseable inputs. Adds a "wildcard segment constraint resolves to concrete version" subtest to TestResolveOCIConstraintVersion so the end-to-end pipeline is exercised for a version string that has no operator characters. Signed-off-by: Samuel Archambault <samuel.archambault@getmaintainx.com> * test: add getOCIChart integration test proving cache-path/pull-flag wiring Address Copilot review feedback on PR #2768. The existing unit test exercised resolveOCIConstraintVersion in isolation but did not prove that its output was propagated into the downstream cache key, cache path, and `helm chart pull --version` flag. Add a targeted integration test that: 1. Calls getOCIChart with a constraint release (`~1`) and a helm mock whose ShowChartWithFlags returns Chart.yaml version 1.0.1. 2. Asserts helm chart pull receives `--version 1.0.1`, not `~1`. 3. Asserts the destination path passed to helm chart pull contains the resolved-version segment (`/1.0.1/`) and does NOT contain the raw-constraint segment (`/_1/`). 4. Reads back the on-disk Chart.yaml under the cache path to confirm resolved version, path, and flag agree end to end. Add a second test that runs the same release twice with different resolver outputs (1.0.1, then 1.0.2 — simulating a newly published matching tag) and asserts the two resolutions land in distinct cache directories. This is the promise of the fix: once the raw constraint is out of the path, a new matching tag stops silently reusing the previously-resolved cache entry. The integration test flushed out a real correctness gap in the initial fix: getOCIChart resolved release.Version and chartVersion but did NOT recompute the qualified OCI ref that getOCIQualifiedChartName built pre-resolution. Helm was therefore receiving `oci://<repo>/<chart>:<constraint>` alongside a `--version <resolved>` flag — at best redundant, at worst rejected by future Helm versions. Fixed by re-invoking getOCIQualifiedChartName on the mutated release copy so the embedded tag also carries the resolved value. Isolates the shared helmfile cache via `t.Setenv(HELMFILE_CACHE_HOME, t.TempDir())` so the OutputDirTemplate == "" code path (which writes into remote.CacheDir) does not touch the user's real `~/.cache/helmfile` during test runs. Signed-off-by: Samuel Archambault <samuel.archambault@getmaintainx.com> * refactor: flatten OCI constraint-resolution wiring in getOCIChart Address review feedback on PR #2768: - Extract the inline resolve/requalify block from getOCIChart into applyOCIConstraintResolution, keeping getOCIChart flat (guard-clause style) and making the resolution wiring independently testable. The helper returns the (possibly updated) release, qualified chart name, and chart version; every failure mode returns its inputs unchanged. - On a re-qualify failure after a successful resolution, fall back to the pre-fix behavior entirely (raw constraint in cache key, ref, AND --version flag) instead of the previous half-resolved mix (resolved version in the cache key, raw constraint in the path and flag), which could desynchronize the in-process cache key from the on-disk path. - Build the 'helm show chart' ref by reusing parseOCIChartRef instead of re-implementing its last-slash/last-colon tag-splitting inline. Same behavior for all realistic refs (registry ports preserved), and it also handles the digest suffix should one ever reach this point. - Drop --devel from the resolver flags: helm documents --devel as ignored whenever --version is set, and --version is always passed on this path. No behavior change intended beyond the requalify-failure fallback (which cannot realistically trigger) and the removal of the inert --devel flag. Signed-off-by: yxxhero <aiopsclub@163.com> * fix: classify partial semver versions (1, 1.2) as OCI constraints Address review feedback on PR #2768: Masterminds' lenient parser accepts partial versions like "1" or "1.2" as versions, so the previous classifier (NewVersion fails && NewConstraint succeeds) treated them as exact pins. But helm's OCI resolution — registry.GetTagMatchingVersionOrConstraint — honors a version string as an exact pin ONLY when a registry tag literally equals it; otherwise it parses the string as a constraint, and "1"/"1.2" float across 1.x.y/1.2.y tags. Caching those under their raw spelling reproduces the stale-cache bug of issue #2766, just with a narrower trigger. Replace the NewVersion probe with isFullSemver, which additionally requires the whole major.minor.patch triple to be spelled out (optional v prefix, prerelease, and build metadata all still count as exact when the core is fully qualified). When a registry does carry a literal tag equal to the version string, the resolver's metadata.Version == chartVersion path reports no change, so literal-tag pins keep today's behavior. TestIsVersionConstraint: "1"/"1.0" flip to constraints, joined by new v1.2/0/v1 cases and a 1.2.3 exact case. TestResolveOCIConstraintVersion gains a "partial version resolves" subtest. Docs updated to describe the parser-based classification instead of "constraint characters". Signed-off-by: yxxhero <aiopsclub@163.com> * fix: skip OCI constraint resolution under skipRefresh Address review feedback on PR #2768: the resolver ran even under --skip-refresh, so offline and cache-only workflows gained a 'helm show chart' registry attempt per constraint-versioned OCI release. It degraded gracefully (warn + fallback), but added registry-timeout latency and warning noise per release. skipOCIConstraintResolution now suppresses resolution when any of the skipRefresh levels is set — CLI --skip-refresh (forced), per-release skipRefresh, or helmDefaults.skipRefresh — with the same precedence the other skipRefresh consumers in prepareChartForRelease use. Skipped runs fall back to the constraint-keyed cache path, i.e. they reuse whatever a previous non-skipped run resolved, which is what 'skip checking for updates to cached charts' means for constraint versions. The existing issue #2766 integration tests flip their opts to SkipRefresh: false since they assert resolution happens. New coverage: TestSkipOCIConstraintResolution (tri-state precedence table) and TestGetOCIChart_SkipRefreshSkipsConstraintResolution (no inspector call, raw constraint in --version and cache path). Signed-off-by: yxxhero <aiopsclub@163.com> * perf: memoize OCI constraint resolution per chart+constraint Address review feedback on PR #2768: resolution ran before the in-process chart-cache fast path and was not memoized, so every constraint-versioned OCI release paid its own 'helm show chart' registry round-trip on every render — including N releases sharing the same chart+constraint, whose parallel workers could even resolve to different versions if the registry changed between their lookups. Memoize successful resolutions in resolvedOCIConstraints keyed by (chart ref, constraint), mirroring the downloadedCharts pattern: - Releases sharing a chart+constraint cost one round-trip per process and consistently use one resolved version per run. - Only successful resolutions are memoized; failures may be transient. - Flags are not part of the key: they govern TLS/verification/registry credentials, not which tag a constraint matches (--devel is already omitted as it is ignored whenever --version is set). - Concurrent misses may both hit the registry; last write wins, harmlessly. resetResolvedOCIConstraintsForTest is added alongside the existing resetChartCacheForTest and wired into the issue #2766 tests — notably ResolvesToDifferentVersionsPicksSeparateCachePaths, which reuses the same chart+constraint across its two runs and would otherwise be served the first resolution from the memo (which is exactly the intended per-process semantics). New coverage: TestResolveOCIConstraintVersion_Memoized (memo hit skips the registry, different constraint is a different key) and TestGetOCIChart_SharedConstraintResolvedOncePerProcess (two releases, one inspector call, one pull, same path). Signed-off-by: yxxhero <aiopsclub@163.com> * test: cover URL-embedded OCI constraint resolution Address review feedback on PR #2768: the existing integration tests only exercised the repo-aliased spelling (chart: myrepo/mychart, version: '~1') and the version-field spelling. The chart-URL spelling (chart: oci://<registry>/<chart>:~1) takes a different branch in getOCIQualifiedChartName — the URL version is deliberately NOT embedded into the qualified ref and flows through --version only — so its re-qualification after constraint resolution (release.Version mutated to the resolved value, versionInURL still the constraint) was untested. TestGetOCIChart_URLEmbeddedConstraintResolves asserts the resolver receives the URL-embedded constraint, helm chart pull receives the resolved version via --version with a tag-less ref, and the cache path carries the resolved version segment instead of the raw constraint. Also gofmt-aligns the test tables added in earlier commits and drops a redundant 1.2.3 test case that tripped goconst. Signed-off-by: yxxhero <aiopsclub@163.com> * docs: note empty-version OCI releases are unaffected by resolveOCIVersions Releases with no version: at all keep their pre-existing semantics: helm picks the latest tag at pull time and helmfile caches it under a version-less shared-cache path. Document the limitation alongside the other resolveOCIVersions scope notes. Signed-off-by: yxxhero <aiopsclub@163.com> --------- Signed-off-by: Samuel Archambault <samuel.archambault@getmaintainx.com> Signed-off-by: yxxhero <aiopsclub@163.com> Co-authored-by: Samuel Archambault <samuel.archambault@getmaintainx.com> Co-authored-by: yxxhero <aiopsclub@163.com>
30 KiB
Configuration Reference
This page is a comprehensive reference for all options available in helmfile.yaml.
If you're new to Helmfile, start with the Getting Started tutorial on the home page, then read Writing Helmfile for patterns. Come back here when you need to look up a specific field.
CAUTION: This documentation is for the development version of Helmfile. If you are looking for the documentation for any of releases, please switch to the corresponding release tag like v0.143.4.
Quick Reference
A helmfile.yaml has these top-level sections:
| Section | Purpose |
|---|---|
repositories |
Helm chart repositories to use |
releases |
The Helm releases to deploy (the core of helmfile) |
helmDefaults |
Default Helm options for all releases |
environments |
Environment-specific values (dev, staging, prod) |
helmfiles |
Include other helmfile.yaml files (nesting) |
bases |
Shared base files merged before this helmfile |
values |
Default values available in templates |
commonLabels |
Labels applied to all releases |
templates |
Reusable release templates |
defaultInherit |
Default template(s) for all releases to inherit |
hooks |
Global lifecycle hooks |
apiVersions / kubeVersion |
Kubernetes version capabilities |
llm |
OpenAI-compatible LLM config for helmfile doctor (optional) |
Full Reference
The default name for a helmfile is helmfile.yaml:
# Chart repositories used from within this state file
#
# Use `helm-s3` and `helm-git` and whatever Helm Downloader plugins
# to use repositories other than the official repository or one backend by chartmuseum.
repositories:
# To use official "stable" charts a.k.a https://github.com/helm/charts/tree/master/stable
- name: stable
url: https://charts.helm.sh/stable
# To use official "incubator" charts a.k.a https://github.com/helm/charts/tree/master/incubator
- name: incubator
url: https://charts.helm.sh/incubator
# helm-git powered repository: You can treat any Git repository as a charts repository
- name: polaris
url: git+https://github.com/reactiveops/polaris@deploy/helm?ref=master
# Advanced configuration: You can setup basic or tls auth and optionally enable helm OCI integration
- name: roboll
url: roboll.io/charts
certFile: optional_client_cert
keyFile: optional_client_key
# username is retrieved from the environment with the format <registryNameUpperCase>_USERNAME for CI usage, here ROBOLL_USERNAME
username: optional_username
# password is retrieved from the environment with the format <registryNameUpperCase>_PASSWORD for CI usage, here ROBOLL_PASSWORD
password: optional_password
oci: true
passCredentials: true
verify: true
keyring: path/to/keyring.gpg
# Advanced configuration: You can use a ca bundle to use an https repo
# with a self-signed certificate
- name: insecure
url: https://charts.my-insecure-domain.com
caFile: optional_ca_crt
# Advanced configuration: You can skip the verification of TLS for an https repo
- name: skipTLS
url: https://ss.my-insecure-domain.com
skipTLSVerify: true
# Advanced configuration: Connect to a repo served over plain http
- name: plainHTTP
url: http://just.http.domain.com
plainHttp: true
# context: kube-context # this directive is deprecated, please consider using helmDefaults.kubeContext
# Path to alternative helm binary (--helm-binary)
# Supports both Helm 3.x and Helm 4.x
helmBinary: path/to/helm
# Path to alternative kustomize binary (--kustomize-binary)
kustomizeBinary: path/to/kustomize
# Path to alternative lock file. The default is <state file name>.lock, i.e for helmfile.yaml it's helmfile.lock.
lockFilePath: path/to/lock.file
# Default values to set for args along with dedicated keys that can be set by contributors, cli args take precedence over these.
# In other words, unset values results in no flags passed to helm.
# See the helm usage (helm SUBCOMMAND -h) for more info on default values when those flags aren't provided.
helmDefaults:
kubeContext: kube-context #dedicated default key for kube-context (--kube-context)
cleanupOnFail: false #dedicated default key for helm flag --cleanup-on-fail
# additional and global args passed to helm (default "")
args:
- "--set k=v"
diffArgs:
- "--suppress-secrets"
syncArgs:
- "--labels=app.kubernetes.io/managed-by=helmfile"
# extra args appended to the helm template / helm diff rendering (default "").
# most commonly "--dry-run=server" to enable the helm lookup() function.
# overridden by the --template-args CLI flag on a per-invocation basis.
templateArgs:
- "--dry-run=server"
# verify the chart before upgrading (only works with packaged charts not directories) (default false)
verify: true
keyring: path/to/keyring.gpg
# --skip-schema-validation flag to helm 'install', 'upgrade' and 'lint' (default false)
skipSchemaValidation: false
# wait for k8s resources via --wait. (default false)
wait: true
# DEPRECATED: waitRetries is no longer supported as the --wait-retries flag was removed from Helm.
# This configuration is ignored and preserved only for backward compatibility.
# waitRetries: 3
# if set and --wait enabled, will wait until all Jobs have been completed before marking the release as successful. It will wait for as long as --timeout (default false)
waitForJobs: true
# time in seconds to wait for any individual Kubernetes operation (like Jobs for hooks, and waits on pod/pvc/svc/deployment readiness) (default 300)
timeout: 600
# performs pods restart for the resource if applicable (default false)
recreatePods: true
# forces resource update through delete/recreate if needed (default false)
force: false
# limit the maximum number of revisions saved per release. Use 0 for no limit. (default 10)
historyMax: 10
# automatically create release namespaces if they do not exist (default true)
createNamespace: true
# if used with charts museum allows to pull unstable charts for deployment, for example: if 1.2.3 and 1.2.4-dev versions exist and set to true, 1.2.4-dev will be pulled (default false)
devel: true
# When set to `true`, skips running `helm dep up` and `helm dep build` on this release's chart.
# Useful when the chart is broken, like seen in https://github.com/roboll/helmfile/issues/1547
skipDeps: false
# When set to `true` (default), resolves an OCI chart's semver constraint
# (e.g. `~1`, `^2.0.0`, `*`, `1.x`, or any version that is not a
# fully-qualified `X.Y.Z` semver — including partial versions like `1` or
# `1.2`, which helm resolves as floating ranges) to a concrete registry tag
# before deriving the on-disk cache path under `$XDG_CACHE_HOME/helmfile`.
# This keeps the cache content-addressable so a newer matching tag is picked
# up on the next run instead of the previously-resolved (now stale) version.
# Set to `false` to preserve the pre-fix behavior of caching under the raw
# constraint string. Resolution is also skipped when skipRefresh is enabled
# (CLI `--skip-refresh`, per-release, or here): helmfile then reuses whatever
# a previous run resolved. Releases with no `version:` at all are also
# unaffected: helm picks the latest tag at pull time and helmfile caches it
# under a version-less path (same as before this setting existed). Exact
# `X.Y.Z` versions (e.g. `1.0.1`) and non-OCI releases are unaffected. See
# issue #2766.
resolveOCIVersions: true
# If set to true, reuses the last release's values and merges them with ones provided in helmfile.
# This attribute, can be overriden in CLI with --reset/reuse-values flag of apply/sync/diff subcommands
reuseValues: false
# propagate `--post-renderer` to helmv3 template and helm install
postRenderer: "path/to/postRenderer"
# propagate `--post-renderer-args` to helmv3 template and helm install. This allows using Powershell
# scripts on Windows as a post renderer
postRendererArgs:
- PowerShell
- "-Command"
- "theScript.ps1"
# cascade `--cascade` to helmv3 delete, available values: background, foreground, or orphan, default: background
cascade: "background"
# insecureSkipTLSVerify is true if the TLS verification should be skipped when fetching remote chart
insecureSkipTLSVerify: false
# plainHttp is true if fetching the remote chart should be done using HTTP
plainHttp: false
# --wait flag for destroy/delete, if set to true, will wait until all resources are deleted before mark delete command as successful
deleteWait: false
# Timeout is the time in seconds to wait for helmfile destroy/delete (default 300)
deleteTimeout: 300
# suppressOutputLineRegex is a list of regex patterns to suppress output lines from helm diff (default []), available in helmfile v0.162.0
suppressOutputLineRegex:
- "version"
# syncReleaseLabels is a list of labels to be added to the release when syncing.
syncReleaseLabels: false
# these labels will be applied to all releases in a Helmfile. Useful in templating if you have a helmfile per environment or customer and don't want to copy the same label to each release
commonLabels:
hello: world
# The desired states of Helm releases.
#
# Helmfile runs various helm commands to converge the current state in the live cluster to the desired state defined here.
releases:
# Published chart example
- name: vault # name of this release
namespace: vault # target namespace
createNamespace: true # automatically create release namespace (default true)
labels: # Arbitrary key value pairs for filtering releases
foo: bar
chart: roboll/vault-secret-manager # the chart being installed to create this release, referenced by `repository/chart` syntax
version: ~1.24.1 # the semver of the chart. range constraint is supported
condition: vault.enabled # Filters releases by the boolean value at `vault.enabled`. Can also be set directly to true or false.
missingFileHandler: Warn # set to either "Error" or "Warn". "Error" instructs helmfile to fail when unable to find a values or secrets file. When "Warn", it prints the file and continues.
missingFileHandlerConfig:
# Ignores missing git branch error so that the Debug/Info/Warn handler can treat a missing branch as non-error.
# See https://github.com/helmfile/helmfile/issues/392
ignoreMissingGitBranch: true
# Values files used for rendering the chart
values:
# Value files passed via --values
- vault.yaml
# Inline values, passed via a temporary values file and --values, so that it doesn't suffer from type issues like --set
- address: https://vault.example.com
# Go template available in inline values and values files.
- image:
# The end result is more or less YAML. So do `quote` to prevent number-like strings from accidentally parsed into numbers!
# See https://github.com/roboll/helmfile/issues/608
tag: {{ requiredEnv "IMAGE_TAG" | quote }}
# Otherwise:
# tag: "{{ requiredEnv "IMAGE_TAG" }}"
# tag: !!string {{ requiredEnv "IMAGE_TAG" }}
db:
username: {{ requiredEnv "DB_USERNAME" }}
# value taken from environment variable. Quotes are necessary. Will throw an error if the environment variable is not set. $DB_PASSWORD needs to be set in the calling environment ex: export DB_PASSWORD='password1'
password: {{ requiredEnv "DB_PASSWORD" }}
proxy:
# Interpolate environment variable with a fixed string
domain: {{ requiredEnv "PLATFORM_ID" }}.my-domain.com
scheme: {{ env "SCHEME" | default "https" }}
# Use `values` whenever possible!
# `setString` translates to helm's `--set-string key=val`
setString:
# set a single array value in an array, translates to --set-string bar[0]={1,2}
- name: bar[0]
values:
- 1
- 2
# set a templated value
- name: namespace
value: {{ .Namespace }}
# `set` translates to helm's `--set key=val`, that is known to suffer from type issues like https://github.com/roboll/helmfile/issues/608
set:
# single value loaded from a local file, translates to --set-file foo.config=path/to/file
- name: foo.config
file: path/to/file
# set a single array value in an array, translates to --set bar[0]={1,2}
- name: bar[0]
values:
- 1
- 2
# set a templated value
- name: namespace
value: {{ .Namespace }}
# will attempt to decrypt it using helm-secrets plugin
secrets:
- vault_secret.yaml
# Override helmDefaults options for verify, wait, waitForJobs, timeout, recreatePods, force and reuseValues.
verify: true
keyring: path/to/keyring.gpg
# --skip-schema-validation flag to helm 'install', 'upgrade' and 'lint' (default false)
skipSchemaValidation: false
wait: true
# DEPRECATED: waitRetries is no longer supported - see documentation above
# waitRetries: 3
waitForJobs: true
timeout: 60
recreatePods: true
force: false
reuseValues: false
# set `false` to uninstall this release on sync. (default true)
installed: true
# Defines the strategy to use when updating. Possible value is:
# - "reinstallIfForbidden": Performs an uninstall before the update only if the update is forbidden (e.g., due to permission issues or conflicts).
updateStrategy: ""
# restores previous state in case of failed release (default false).
# On Helm 4+ this emits --rollback-on-failure (the successor to the deprecated --atomic).
atomic: true
# restores previous state on a failed release via the Helm 4 --rollback-on-failure flag
# (default false). Requires Helm 4 or greater. Mutually exclusive with atomic.
rollbackOnFailure: false
# when true, cleans up any new resources created during a failed release (default false)
cleanupOnFail: false
# --kube-context to be passed to helm commands
# See https://github.com/roboll/helmfile/issues/642
# (default "", which means the standard kubeconfig, either ~/kubeconfig or the file pointed by $KUBECONFIG environment variable)
kubeContext: kube-context
# passes --disable-validation to helm diff plugin, this requires diff plugin >= 3.1.2
# It may be helpful to deploy charts with helm api v1 CRDS
# https://github.com/roboll/helmfile/pull/1373
disableValidation: false
# passes --disable-validation to helm diff plugin, this requires diff plugin >= 3.1.2
# It is useful when any release contains custom resources for CRDs that is not yet installed onto the cluster.
# https://github.com/roboll/helmfile/pull/1618
# To apply this to all releases without editing each one, use the --skip-diff-validation-on-install CLI flag.
disableValidationOnInstall: false
# passes --disable-openapi-validation to helm diff plugin, this requires diff plugin >= 3.1.2
# It may be helpful to deploy charts with helm api v1 CRDS
# https://github.com/roboll/helmfile/pull/1373
disableOpenAPIValidation: false
# limit the maximum number of revisions saved per release. Use 0 for no limit (default 10)
historyMax: 10
# When set to `true`, skips running `helm dep up` and `helm dep build` on this release's chart.
# Useful when the chart is broken, like seen in https://github.com/roboll/helmfile/issues/1547
skipDeps: false
# propagate `--post-renderer` to helmv3 template and helm install
postRenderer: "path/to/postRenderer"
# propagate `--post-renderer-args` to helmv3 template and helm install. This allows using Powershell
# scripts on Windows as a post renderer
postRendererArgs:
- PowerShell
- "-Command"
- "theScript.ps1"
# cascade `--cascade` to helmv3 delete, available values: background, foreground, or orphan, default: background
cascade: "background"
# insecureSkipTLSVerify is true if the TLS verification should be skipped when fetching remote chart
insecureSkipTLSVerify: false
# plainHttp is true if fetching the remote chart should be done using HTTP
plainHttp: false
# suppressDiff skip the helm diff output. Useful for charts which produces large not helpful diff, default: false
suppressDiff: false
# suppressOutputLineRegex is a list of regex patterns to suppress output lines from helm diff (default []), available in helmfile v0.162.0
suppressOutputLineRegex:
- "version"
# syncReleaseLabels is a list of labels to be added to the release when syncing.
syncReleaseLabels: false
# unitTests is a list of test file or directory paths for helm-unittest integration.
# When specified, `helmfile unittest` will run `helm unittest` with the merged values and these test paths.
# Requires the helm-unittest plugin: https://github.com/helm-unittest/helm-unittest
unitTests:
- tests/vault
# Local chart example
- name: grafana # name of this release
namespace: another # target namespace
chart: ../my-charts/grafana # the chart being installed to create this release, referenced by relative path to local helmfile
values:
- "../../my-values/grafana/values.yaml" # Values file (relative path to manifest)
- ./values/{{ requiredEnv "PLATFORM_ENV" }}/config.yaml # Values file taken from path with environment variable. $PLATFORM_ENV must be set in the calling environment.
wait: true
#
# Advanced Configuration: Nested States
#
helmfiles:
- # Path to the helmfile state file being processed BEFORE releases in this state file
path: path/to/subhelmfile.yaml
# Label selector used for filtering releases in the nested state.
# For example, `name=prometheus` in this context is equivalent to processing the nested state like
# helmfile -f path/to/subhelmfile.yaml -l name=prometheus sync
selectors:
- name=prometheus
# Override state values
values:
# Values files merged into the nested state's values
- additional.values.yaml
# One important aspect of using values here is that they first need to be defined in the values section
# of the origin helmfile, so in this example key1 needs to be in the values or environments.NAME.values of path/to/subhelmfile.yaml
# Inline state values merged into the nested state's values
- key1: val1
- # All the nested state files under `helmfiles:` is processed in the order of definition.
# So it can be used for preparation for your main `releases`. An example would be creating CRDs required by `releases` in the parent state file.
path: path/to/mycrd.helmfile.yaml
- # Terraform-module-like URL for importing a remote directory and use a file in it as a nested-state file
# The nested-state file is locally checked-out along with the remote directory containing it.
# Therefore all the local paths in the file are resolved relative to the file
path: git::https://github.com/cloudposse/helmfiles.git@releases/kiam.yaml?ref=0.40.0
- # By default git repositories aren't updated unless the ref is updated.
# Alternatively, refer to a named ref and disable the caching.
path: git::ssh://git@github.com/cloudposse/helmfiles.git@releases/kiam.yaml?ref=main&cache=false
# If set to "Error", return an error when a subhelmfile points to a
# non-existent path. The default behavior is to print a warning and continue.
missingFileHandler: Error
missingFileHandlerConfig:
# Ignores missing git branch error so that the Debug/Info/Warn handler can treat a missing branch as non-error.
# See https://github.com/helmfile/helmfile/issues/392
ignoreMissingGitBranch: true
#
# Advanced Configuration: Environments
#
# The list of environments managed by helmfile.
#
# The default is `environments: {"default": {}}` which implies:
#
# - `{{ .Environment.Name }}` evaluates to "default"
# - `{{ .Values }}` being empty
environments:
# The "default" environment is available and used when `helmfile` is run without `--environment NAME`.
default:
# Everything from the values.yaml is available via `{{ .Values.KEY }}`.
# Suppose `{"foo": {"bar": 1}}` contained in the values.yaml below,
# `{{ .Values.foo.bar }}` is evaluated to `1`.
values:
- environments/default/values.yaml
# Everything from the values.hcl in the `values` block is available via `{{ .Values.KEY }}`.
# More details in its dedicated section
- environments/default/values.hcl
# Each entry in values can be either a file path or inline values.
# The below is an example of inline values, which is merged to the `.Values`
- myChartVer: 1.0.0-dev
# Any environment other than `default` is used only when `helmfile` is run with `--environment NAME`.
# That is, the "production" env below is used when and only when it is run like `helmfile --environment production sync`.
production:
values:
- environments/production/values.yaml
- myChartVer: 1.0.0
# disable vault release processing
- vault:
enabled: false
## `secrets.yaml` is decrypted by `helm-secrets` and available via `{{ .Environment.Values.KEY }}`
secrets:
- environments/production/secrets.yaml
# Instructs helmfile to fail when unable to find a environment values file listed under `environments.NAME.values`.
#
# Possible values are "Error", "Warn", "Info", "Debug". The default is "Error".
#
# Use "Warn", "Info", or "Debug" if you want helmfile to not fail when a values file is missing, while just leaving
# a message about the missing file at the log-level.
missingFileHandler: Error
missingFileHandlerConfig:
# Ignores missing git branch error so that the Debug/Info/Warn handler can treat a missing branch as non-error.
# See https://github.com/helmfile/helmfile/issues/392
ignoreMissingGitBranch: true
# kubeContext to use for this environment
kubeContext: kube-context
#
# Advanced Configuration: Layering
#
# Helmfile merges all the "base" state files and this state file before processing.
#
# Assuming this state file is named `helmfile.yaml`, all the files are merged in the order of:
# environments.yaml <- defaults.yaml <- templates.yaml <- helmfile.yaml
bases:
- environments.yaml
- defaults.yaml
- templates.yaml
#
# Advanced Configuration: API Capabilities
#
# 'helmfile template' renders releases locally without querying an actual cluster,
# and in this case `.Capabilities.APIVersions` cannot be populated.
# When a chart queries for a specific CRD or the Kubernetes version, this can lead to unexpected results.
#
# Note that `Capabilities.KubeVersion` is deprecated in Helm 3 and `helm template` won't populate it.
# All you can do is fix your chart to respect `.Capabilities.APIVersions` instead, rather than trying to figure out
# how to set `Capabilities.KubeVersion` in Helmfile.
#
# Configure a fixed list of API versions to pass to 'helm template' via the --api-versions flag with the below:
apiVersions:
- example/v1
# Set the kubeVersion to render the chart with your desired Kubernetes version.
# The flag --kube-version was deprecated in helm v3 but it was added again.
# For further information https://github.com/helm/helm/issues/7326
kubeVersion: v1.21
Additional helmDefaults fields
The following helmDefaults fields are also available but not shown in the example above:
| Field | Type | Default | Description |
|---|---|---|---|
enableDNS |
bool | false | Enable DNS lookups when rendering templates |
skipCRDs |
bool | false | Skip CRDs during installation |
skipRefresh |
bool | false | Skip running helm dependency up |
resolveOCIVersions |
bool | true | Resolve OCI semver constraints (e.g. ~1, ^2.0.0, *, 1.x, and partial versions like 1.2 that helm treats as floating ranges) to concrete registry tags before deriving the shared cache path. Prevents stale cache hits after new matching tags are published. Set to false to keep the pre-fix behavior. Skipped when skipRefresh is enabled (CLI --skip-refresh, per-release, or helmDefaults). Only affects OCI releases with a non-exact version. See issue #2766 |
atomic |
bool | false | Restore previous state on a failed install/upgrade. On Helm 4+ emits --rollback-on-failure (the successor to the deprecated --atomic); on older Helm emits --atomic |
rollbackOnFailure |
bool | false | Restore previous state on a failed install/upgrade via the Helm 4 --rollback-on-failure flag. Requires Helm 4 or greater. Mutually exclusive with atomic |
forceConflicts |
bool | false | Force server-side apply changes against conflicts (Helm 4 only) |
takeOwnership |
bool | false | Take ownership of existing resources |
serverSide |
string | Controls the helm 4 --server-side flag. Must be "true", "false", or "auto" (Helm 4 only) |
|
trackMode |
string | "" |
Default tracking mode for resources. See Advanced Features |
disableAutoDetectedKubeVersionForDiff |
bool | false | Disable auto-detected kubeVersion being passed to helm diff |
Additional release fields
Condition
condition controls whether a release is enabled. An empty condition enables the release. A direct true or false value is treated as a literal boolean and bypasses values lookup. Any other condition must be a values lookup path ending in .enabled, such as vault.enabled.
conditionTemplate is evaluated before condition is checked. It must render to a boolean value; when both condition and conditionTemplate are set, the rendered conditionTemplate value replaces condition. Like other *Template fields, conditionTemplate is not evaluated by the list command.
The following per-release fields are also available:
| Field | Type | Default | Description |
|---|---|---|---|
valuesTemplate |
list | Like values but template expressions are rendered before being passed to Helm |
|
setTemplate |
list | Like set but template expressions are rendered before being passed to Helm |
|
apiVersions |
list | Per-release API versions (overrides top-level apiVersions) |
|
kubeVersion |
string | Per-release kube version (overrides top-level kubeVersion) |
|
valuesPathPrefix |
string | Prefix for values file paths | |
verifyTemplate |
string | Templated verify flag (e.g., {{ .Values.verify | default "false" }}) |
|
waitTemplate |
string | Templated wait flag | |
installedTemplate |
string | Templated installed flag | |
conditionTemplate |
string | Templated condition flag. Must render to a boolean. When set with condition, the rendered value replaces condition |
|
adopt |
list | List of resources to adopt (passes --adopt to Helm) |
|
forceGoGetter |
bool | false | Force go-getter URL parsing for the chart field. Useful when go-getter URL parsing fails unexpectedly |
forceNamespace |
string | Force namespace on all K8s resources rendered by the chart, even when the template doesn't use {{ .Namespace }}. Use with caution |
|
skipRefresh |
bool | false | Per-release skip for helm dependency up |
resolveOCIVersions |
bool | inherited | Per-release override of the helmDefaults.resolveOCIVersions setting |
disableAutoDetectedKubeVersionForDiff |
bool | false | Disable auto-detected kubeVersion for helm diff on this release |
takeOwnership |
bool | false | Take ownership of existing resources for this release |
serverSide |
string | Controls the helm 4 --server-side flag for this release. Must be "true", "false", or "auto" (Helm 4 only) |
|
forceConflicts |
bool | false | Force server-side apply against conflicts (Helm 4 only) |
description |
string | Description of the release | |
enableDNS |
bool | false | Enable DNS lookups when rendering templates |
Release tracking fields (kubedog)
See Advanced Features for more details:
| Field | Type | Default | Description |
|---|---|---|---|
trackMode |
string | "" |
Track mode: helm, helm-legacy, or kubedog |
trackTimeout |
int | 300 | Tracking timeout in seconds |
trackLogs |
bool | false | Enable real-time log streaming |
trackKinds |
list | Whitelist of resource kinds to track | |
skipKinds |
list | Blacklist of resource kinds to skip | |
trackResources |
list | Specific resources to track (objects with kind, name, namespace) |
|
kubedogQPS |
float | QPS for kubedog kubernetes client | |
kubedogBurst |
int | Burst for kubedog kubernetes client |
Hook kubectlApply
Hooks also support a kubectlApply field for running kubectl apply directly:
releases:
- name: myapp
chart: mychart
hooks:
- events: ["presync"]
showlogs: true
kubectlApply:
filename: manifests/my-resource.yaml
Or with kustomize:
hooks:
- events: ["presync"]
showlogs: true
kubectlApply:
kustomize: overlays/default/
Repository additional fields
| Field | Type | Description |
|---|---|---|
registryConfig |
string | Path to registry configuration file |
managed |
string | Managed repository mode |
Template Partials
Files matching _*.tpl in the same directory as the helmfile are automatically loaded as helper templates. For example, a file named _helpers.tpl can define named templates that are reusable across your helmfile:
_helpers.tpl:
{{- define "myapp.labels" -}}
app: myapp
env: {{ .Environment.Name }}
{{- end -}}
helmfile.yaml:
releases:
- name: myapp
chart: mychart
values:
- labels: {{ include "myapp.labels" . | toYaml | nindent 4 }}
LLM Configuration (doctor)
The optional top-level llm block configures the OpenAI-compatible LLM endpoint
used by helmfile doctor for AI-assisted diff analysis. When absent, doctor
degrades to plain helmfile diff.
llm:
# baseURL is optional. Defaults to https://api.openai.com/v1.
# Set this when using a gateway (One-API, LiteLLM, etc.) or non-OpenAI provider.
baseURL: https://one-api.internal/v1
# apiKey is required. Use template expressions to pull from env:
apiKey: {{ env "HELMFILE_LLM_API_KEY" }}
# model is required (e.g. "gpt-4o", "claude-3-5-sonnet" via gateway, "deepseek-chat").
model: gpt-4o
# Optional: per-request timeout (default: 60s).
timeout: 90s
# Optional: max completion tokens (default: 4096).
maxTokens: 8192
Configuration precedence: environment variables (HELMFILE_LLM_*) < this llm: block < CLI flags (--llm-*). See CLI Reference > doctor for the full documentation including secret redaction, exit codes, and backend compatibility.