Installing and Using Helm

By Vishvesh Patel · DevOps EngineerUpdated September 12, 2026

Install Helm on macOS, Linux or Windows, add repositories, and run the install, upgrade, rollback and uninstall commands that make up the daily workflow.

Helm 3 is a single binary that runs on your machine. There is nothing to install into the cluster. It authenticates with your existing kubeconfig and talks to the Kubernetes API as you.

That means whatever Helm can do, you could already do with kubectl. If your kubeconfig cannot create Deployments in a namespace, neither can Helm.

Install

macOS

brew install helm

Linux

curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash

On Debian or Ubuntu you can use the apt repository instead, which gets you upgrades through the package manager. Piping a script to a shell is convenient but worth reading first on a machine you care about.

Windows

choco install kubernetes-helm

winget install Helm.Helm and scoop install helm both work too.

Verify

helm version
version.BuildInfo{Version:"v3.16.3", GitCommit:"cfd07493f...", GoVersion:"go1.22.7"}

Confirm it is v3.x. Any guide telling you to run helm init or mentioning Tiller is describing Helm 2, which is end-of-life. Helm 3 has no cluster-side component and no initialisation step.

Helm uses the same kubeconfig and current context as kubectl, so check where you are pointed before installing anything:

kubectl config current-context

Repositories

A repository is an index of charts served over HTTP. Add one, then refresh the local cache:

helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
helm repo list
helm search repo nginx
NAME                    CHART VERSION   APP VERSION  DESCRIPTION
bitnami/nginx           18.2.1          1.27.2       NGINX Open Source is a web server...
bitnami/nginx-ingress-controller  11.6.7  1.11.3     NGINX Ingress Controller...

helm repo update is the step people forget. Without it you install whatever version was current when you added the repository, which can be months old. helm search repo only ever searches your local cache.

To search everything published publicly instead, use helm search hub.

Many projects now publish to OCI registries rather than classic repositories, in which case there is no repo add at all. You reference the chart directly:

helm install my-app oci://registry-1.docker.io/bitnamicharts/nginx

Read the values before you install

helm show values bitnami/nginx > nginx-values.yaml

Do this every time. Charts commonly expose a hundred or more settings, and the defaults are tuned for a demo, usually one replica, no resource limits, and persistence switched off. Installing straight from defaults is how you end up with an unlimited pod that gets evicted under memory pressure.

Also worth a look before installing something unfamiliar:

helm show chart bitnami/nginx      # metadata and dependencies
helm show readme bitnami/nginx     # the chart's own documentation
helm template my-nginx bitnami/nginx -f nginx-values.yaml | less   # rendered manifests

Install a chart

helm install my-nginx bitnami/nginx -f nginx-values.yaml

my-nginx is the release name. Your name for this installation, not the chart's name. It must be unique within the namespace.

Namespaces are worth being explicit about, because Helm does not create them for you by default:

helm install monitoring prometheus-community/kube-prometheus-stack \
  --namespace monitoring \
  --create-namespace

For anything automated, prefer the idempotent form. It installs if the release is absent and upgrades if it exists, so the same command works on first run and every run after:

helm upgrade --install my-nginx bitnami/nginx -f nginx-values.yaml

Inspect what is installed

helm list
NAME       NAMESPACE  REVISION  UPDATED                 STATUS    CHART         APP VERSION
my-nginx   default    1         2026-09-12 10:04:11     deployed  nginx-18.2.1  1.27.2

helm list is namespace-scoped. A release you cannot find is usually in another namespace:

helm list -A
helm status my-nginx          # status plus the chart's post-install notes
helm get values my-nginx      # the values you supplied
helm get manifest my-nginx    # exactly what was applied
helm history my-nginx         # every revision

helm get values my-nginx --all shows the merged result of your overrides and the chart defaults, which answers "why is this setting not what I expected" faster than anything else.

Upgrade and roll back

helm upgrade my-nginx bitnami/nginx -f nginx-values.yaml --atomic --timeout 5m

--atomic makes the upgrade all-or-nothing, if the new resources do not become ready within the timeout, Helm reverts the release rather than leaving it half-applied. Use it every time.

helm history my-nginx
helm rollback my-nginx 1

Uninstall

helm uninstall my-nginx

This removes the resources Helm created and the release history. Two things it does not remove:

  • PersistentVolumeClaims, in most charts. Deliberately, so data survives. They keep costing money until you delete them.
  • CRDs installed from the chart's crds/ directory, because removing them would delete every custom resource of that type in the cluster.
# Check for leftovers
kubectl get pvc -n <namespace>

Use --keep-history if you want the release history retained for reference after removal.

Quick reference

TaskCommand
Check the versionhelm version
Add a repositoryhelm repo add <name> <url>
Refresh the cachehelm repo update
Search locallyhelm search repo <term>
Search publiclyhelm search hub <term>
Read a chart's settingshelm show values <chart>
Render without installinghelm template <release> <chart>
Installhelm install <release> <chart> -f values.yaml
Install or upgradehelm upgrade --install <release> <chart>
All releaseshelm list -A
Applied valueshelm get values <release> --all
Historyhelm history <release>
Roll backhelm rollback <release> <revision>
Uninstallhelm uninstall <release>

Key takeaways

  • Helm 3 is a local binary. Nothing is installed into the cluster; it uses your kubeconfig and your permissions.
  • helm init and Tiller are Helm 2. If a guide mentions them, it is out of date.
  • Run helm repo update or you will install a stale chart version from your local cache.
  • Always helm show values first. Chart defaults are demo defaults.
  • helm upgrade --install is the idempotent form to use in automation.
  • helm list is namespace-scoped: use -A when a release seems to have vanished.
  • Uninstall leaves PVCs and CRDs behind, on purpose. Check for orphaned claims afterwards.

Check your understanding

Exercise

A release that disappeared

A colleague installed a release yesterday, but helm list on your machine shows nothing. Both of you use the same cluster and the same kubeconfig. What is the most likely explanation?

Exercise

Storage costs after an uninstall

You run helm uninstall on a database release. Weeks later the cloud bill still shows the volume. Why?


Frequently Asked Questions

How do I install Helm?

Use your platform's package manager: brew install helm on macOS, choco install kubernetes-helm or winget install Helm.Helm on Windows, and either the official install script or the apt repository on Linux. Confirm with helm version that you have v3.x. There is no cluster-side installation step. Helm 3 is a client that uses your existing kubeconfig, so if kubectl works, Helm works.

Do I still need to run helm init or install Tiller?

No. helm init and Tiller belong to Helm 2, which reached end of life. Tiller was a cluster-side service that usually held broad permissions and was a recognised security risk. Helm 3 removed it: the client talks directly to the Kubernetes API using your credentials, and release state is stored as Secrets in each release's namespace. Any tutorial mentioning helm init is out of date and should be treated with suspicion generally.

What is the difference between helm install and helm upgrade --install?

helm install fails if a release with that name already exists. helm upgrade --install installs it when absent and upgrades it when present, making the command idempotent. That is what you want in CI or any script that may run more than once, since it removes the need to check state first. Adding --atomic makes it safer still by rolling back automatically if the release does not become ready.

Why can't Helm find my release?

helm list only shows releases in the current namespace, because Helm 3 stores release state as Secrets in the namespace where the release lives. Run helm list -A to search every namespace, or helm list -n <namespace> to target one. If it is still missing, confirm you are on the expected cluster with kubectl config current-context. Pointing at the wrong context is the other common cause.

Does helm uninstall delete everything?

Not quite, and the exceptions are deliberate. PersistentVolumeClaims are usually left in place so that uninstalling an application does not destroy its data, which means the underlying cloud volumes keep incurring cost until you delete the claims yourself. CRDs installed from a chart's crds/ directory are also left alone, because deleting a CRD would delete every custom resource of that type across the cluster. After uninstalling anything stateful, check kubectl get pvc in that namespace.

How do I see what a chart will actually create before installing it?

helm template <release-name> <chart> -f values.yaml renders the chart locally and prints the full set of manifests without contacting the cluster. This is the best way to review a third-party chart before trusting it, and to debug your own templates. helm install --dry-run --debug does something similar but validates against the live API server, which additionally catches schema problems and missing CRDs. Pair either with helm show values so you know which settings are available to change.

Continue Learning

Explore Related Topics

Try the Tool

Practise this in the browser

Kubernetes Playground

Practise kubectl against a simulated cluster in your browser.

When it breaks

Related Resources