Skip to content
LatchkeyLatchkey home

helmfile apply: Diff Then Sync Releases

helmfile apply computes a diff and upgrades only the releases that actually changed, making it the efficient deploy command.

apply is the workhorse: it diffs every release in helmfile.yaml and applies just the ones with changes, so it is fast and noise-free in CI.

What it does

helmfile apply renders all releases, diffs them against the cluster using helm-diff, and runs helm upgrade --install only for releases that differ. Unchanged releases are skipped, so repeated runs are cheap. It needs the helm-diff plugin.

Common usage

Terminal
helmfile -e production apply
# apply only a subset by label
helmfile apply --selector tier=frontend
# skip the diff for brand-new installs (faster first deploy)
helmfile apply --skip-diff-on-install

Options

FlagWhat it does
-e, --environment <name>Select an environment block
--selector key=valueApply only releases matching the label
--skip-diff-on-installDo not diff releases that are not yet installed
--suppress-secretsHide secret values in the diff output
--waitPass helm --wait so it blocks on readiness

In CI

apply is preferred over sync in pipelines because it only touches changed releases, keeping logs clean and runs fast. Pin the environment with -e so the right values file loads. Add --wait when you want the job to fail on an unhealthy rollout.

Common errors in CI

"Error: unknown command \"diff\" for \"helm\"" means the helm-diff plugin is missing; run helmfile init --force. "in ./helmfile.yaml: failed to read ... environment values" means an environment or values file is missing. "Error: UPGRADE FAILED: another operation (install/upgrade/rollback) is in progress" means a prior helm operation is stuck; roll it back or delete the pending release.

Using this in CI

A runner has no kubeconfig, no cached context, and no interactive auth. Every kubectl invocation in CI needs the context supplied explicitly, and most confusing CI failures here are the command running against the wrong cluster or no cluster at all.

Terminal
# never rely on the ambient context on a runner
kubectl --context "$KUBE_CONTEXT" -n "$NAMESPACE" get pods

# confirm what you are actually connected to before mutating anything
kubectl config current-context
kubectl cluster-info

# fail fast instead of hanging on an unreachable API server
kubectl --request-timeout=30s get nodes

Frequently asked questions

helmfile apply: Diff Then Sync Releases?
apply is the workhorse: it diffs every release in helmfile.yaml and applies just the ones with changes, so it is fast and noise-free in CI.
What it does?
helmfile apply renders all releases, diffs them against the cluster using helm-diff, and runs helm upgrade --install only for releases that differ. Unchanged releases are skipped, so repeated runs are cheap. It needs the helm-diff plugin.
In CI?
apply is preferred over sync in pipelines because it only touches changed releases, keeping logs clean and runs fast. Pin the environment with -e so the right values file loads. Add --wait when you want the job to fail on an unhealthy rollout.
Common errors in CI?
"Error: unknown command \"diff\" for \"helm\"" means the helm-diff plugin is missing; run helmfile init --force. "in ./helmfile.yaml: failed to read ... environment values" means an environment or values file is missing.

Related guides

References

Run this faster and cheaper on Latchkey managed runners - self-healing included. Start free → 30-day trial · No credit card