What Is Helm? Helm Charts and Package Management for Kubernetes Explained

Helm is the package manager for Kubernetes. Instead of applying a dozen separate YAML files every time you deploy or update an application, Helm bundles them into a single versioned unit called a Chart, which you can install, upgrade, and roll back with one command. On Google Kubernetes Engine, Helm is the standard way to manage repeatable application deployments and deploy third-party tools like ingress controllers, monitoring stacks, and certificate managers.

Helm in plain English

When you deploy an application to Kubernetes, you need multiple resources working together: a Deployment to run your pods, a Service to expose them, an Ingress to route external traffic, a ConfigMap for configuration, and possibly a Secret, an HPA, and a PodDisruptionBudget. Each resource is a separate YAML file.

That is manageable for one environment. It becomes hard work when you have dev, staging, and production. Each environment will have slightly different replica counts, resource limits, hostnames, and image tags. Keeping those files in sync manually is error-prone.

Helm solves this by treating a whole application as a single installable package. The templates stay consistent; the values differ per environment. You install the package with one command, upgrade it with one command, and roll it back with one command.

Analogy

Think of a Helm Chart like a recipe. The recipe (templates) stays consistent, but you adjust the quantities (values) for two people or twenty. Helm also keeps a record of every meal you have made from that recipe, so you can recreate or undo any previous version.

Why Helm exists

Without Helm, you face two bad options:

  1. Duplicate YAML files for each environment. You end up with three copies of every manifest, manually kept in sync. Any change must be applied to all three. Drift creeps in quickly.
  2. Fragile shell scripts with sed replacements. You template values into YAML by string substitution. This works until it does not, and debugging it is unpleasant.

Helm solves this with two things:

  • Templating: values like image tags, replica counts, and domain names become variables. One set of templates serves all environments; only the values file changes.
  • Versioned releases: every install or upgrade is recorded. You can roll back to any previous state with a single command, and the history tells you exactly what changed and when.

How Helm works

Here is the full flow from a Chart to a running application:

  1. Chart. You start with a Chart: a directory containing Kubernetes template files, a values.yaml file with defaults, and a Chart.yaml file with metadata. The templates use Go template syntax to inject values.

  2. Values. You provide values at install time, either by overriding individual keys with --set, or by supplying a values.yaml file with -f. These replace the template variables.

  3. Rendering. Helm combines the templates and values to produce plain Kubernetes YAML. This step happens entirely on the client side.

  4. Apply. Helm sends the rendered YAML to the Kubernetes API server, the same way kubectl apply would. The cluster creates or updates the resources.

  5. Release. Helm creates a Release: a named, tracked instance of the Chart. Release state is stored as a Kubernetes Secret in the cluster.

  6. Revision history. Each upgrade creates a new revision. Helm keeps a numbered history of every change, including Chart version, values, and timestamps.

  7. Upgrade. Run helm upgrade to apply a new version of the Chart or updated values. Helm calculates what has changed and applies only those differences.

  8. Rollback. If an upgrade causes problems, run helm rollback to restore any previous revision instantly.

Dry run before you commit

Before applying any install or upgrade, run helm template RELEASE_NAME CHART_PATH -f values.yaml to render the full output locally without touching the cluster. Pair this with helm lint ./chart-dir to catch template errors early. These two commands together are the fastest way to sanity-check a Chart.

Helm v3: no Tiller, proper RBAC

Helm v3, released in November 2019, removed Tiller entirely. In Helm v2, Tiller was a server-side pod that ran inside your cluster with broad permissions. Anyone who could reach Tiller could effectively do anything on the cluster, regardless of their own RBAC permissions. This was a genuine security problem.

Helm v3 communicates directly with the Kubernetes API server using your own kubeconfig credentials. This changes several things:

  • Helm respects your RBAC permissions. It cannot do anything your credentials cannot do.
  • Release state is stored as Kubernetes Secrets in the same namespace as the release. Each namespace has its own isolated history.
  • No privileged server-side component. Nothing to maintain, patch, or secure.
If you see helm init in a tutorial

helm init and anything about Tiller applies to the deprecated Helm v2. Helm v3 requires no initialisation step. Install the CLI and start using it immediately.

Core concepts

Chart

A Helm package. It is a directory (or compressed .tgz archive) containing:

  • Chart.yaml — metadata: name, version, description, and API version
  • values.yaml — default configuration values that can be overridden
  • templates/ — Kubernetes YAML files with Go template syntax for variable substitution
  • charts/ — optional directory for dependency Charts

Release

A deployed instance of a Chart on a cluster. When you install a Chart, Helm creates a Release with a name you choose. You can install the same Chart multiple times under different names. For example: two separate PostgreSQL installations for different applications, each with its own independent history.

Repository

A location where Charts are stored and shared. Artifact Hub (https://artifacthub.io) indexes thousands of publicly available Charts. Organisations often host private repositories for internal Charts.

Revision

Each install or upgrade increments the revision number. Helm stores the state at every revision, enabling rollbacks to any point in the release history.

Managing repositories

Before installing a Chart from a public repository, add that repository to your local Helm configuration:

# Add the Bitnami repository
helm repo add bitnami https://charts.bitnami.com/bitnami

# Add the ingress-nginx repository
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx

# Update all local repository indexes
helm repo update

# Search for Charts across all added repositories
helm search repo nginx

# Search for a specific Chart and show available versions
helm search repo bitnami/postgresql --versions
Always update before you install

Local repository indexes go stale quickly. Running helm repo update before every install or upgrade ensures you see the latest available versions and avoid installing something outdated without realising it.

Installing, upgrading, and uninstalling Charts

Installing a Chart:

helm install my-release bitnami/nginx \
  --namespace web \
  --create-namespace

This installs the bitnami/nginx Chart as a Release named my-release in the web namespace, creating the namespace if it does not exist.

Listing installed releases:

helm list -n web
helm list -A   # across all namespaces

Upgrading a release:

helm upgrade my-release bitnami/nginx \
  --namespace web \
  --set replicaCount=3

Every upgrade creates a new revision. The release history records each revision’s Chart version, values, and timestamps.

Viewing release history:

helm history my-release -n web

Rolling back to a previous revision:

# Roll back to the previous revision
helm rollback my-release -n web

# Roll back to a specific revision number
helm rollback my-release 2 -n web

Uninstalling a release:

helm uninstall my-release -n web

This removes all Kubernetes resources created by the release. By default it also deletes the release history; use --keep-history to retain it for auditing or potential rollback.

Overriding default values

Every Chart ships with values.yaml containing sensible defaults. Override them at install or upgrade time in two ways.

Using --set for individual values:

helm install my-db bitnami/postgresql \
  --namespace database \
  --set auth.postgresPassword=supersecret \
  --set primary.persistence.size=20Gi

--set is convenient for one or two values, but it becomes hard to review, audit, or version-control with many overrides.

Using a values file with -f:

helm install my-db bitnami/postgresql \
  --namespace database \
  -f values-production.yaml

Where values-production.yaml contains only the keys you want to override:

auth:
  postgresPassword: supersecret
primary:
  persistence:
    size: 20Gi
  resources:
    requests:
      cpu: "500m"
      memory: "1Gi"

You can layer multiple -f flags; later files take precedence. A common pattern is -f values.yaml -f values-production.yaml, where the second file overrides only the production-specific differences.

Keep secrets out of values files

Avoid committing passwords and secrets directly into values files stored in version control. Use Kubernetes Secrets or a secrets manager such as Google Secret Manager, and reference them in your Chart templates rather than passing raw values through Helm.

Creating your own Chart

To package your own application, scaffold a new Chart:

helm create my-app

This creates a my-app/ directory with a standard structure including a Deployment template, Service template, Ingress template, HPA template, and a _helpers.tpl file for reusable template fragments.

The generated templates use Go template syntax. For example, the replica count in deployment.yaml reads:

replicas: {{ .Values.replicaCount }}

And the image tag reads:

image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"

When you run helm install, Helm renders these templates by substituting values from values.yaml and any overrides you provide, then sends the resulting plain YAML to the Kubernetes API server. It behaves identically to kubectl apply, but the result is tracked as a named release.

Validating your Chart before installing:

# Render templates locally without applying them
helm template my-app ./my-app -f values-production.yaml

# Validate the Chart structure and templates
helm lint ./my-app

Installing and packaging your Chart:

# Install from a local directory
helm install my-app ./my-app \
  --namespace production \
  -f values-production.yaml

# Package for distribution
helm package ./my-app
# Produces my-app-0.1.0.tgz

When to use Helm

Helm is worth using when one or more of these apply:

  • Deploying third-party tools onto GKE. Ingress controllers, cert-managers, monitoring stacks (Prometheus, Grafana), and PostgreSQL all have maintained public charts. Installing them via Helm is faster and more reliable than writing manifests from scratch.
  • Managing the same application across multiple environments. One chart, three values files: dev, staging, production. Each environment is consistent with the others except where you deliberately differ.
  • You need upgrade and rollback. If something breaks after a deploy, helm rollback restores the previous state in seconds. Without Helm, you would need to track down the previous manifests manually.
  • Packaging your own application for reuse. If the same service is deployed into multiple clusters or by multiple teams, a Helm Chart gives you a consistent, versioned artefact.
  • Working in a CI/CD pipeline. Helm integrates cleanly into pipelines. You can pass environment-specific values at deploy time from pipeline variables, keeping configuration separate from application code. See Cloud Deploy overview for how GCP handles this.
Common GKE starting point

On GKE, the first thing most teams install with Helm is an ingress controller. A single helm install sets up the controller, the LoadBalancer Service, and the default backend in one step, with upgrade and rollback available from day one.

When Helm may not be necessary

Helm adds some complexity. It may not be the right choice when:

  • You have one or two small manifests with no environment variation. A single static Deployment and Service applied with kubectl apply is simpler and easier to understand.
  • You are learning Kubernetes basics. Start with raw manifests so you understand what each resource does. Helm abstracts some of that, which can slow down learning.
  • Your team has standardised on Kustomize. Both tools solve similar problems differently. If Kustomize is already established, adding Helm for the same purpose creates friction.
  • You do not need release history or rollback. Some teams track changes through Git history and re-apply manifests from source. If your workflow already handles rollback through version control, Helm’s release history adds overhead without benefit.

Helm vs kubectl vs Kustomize

These three tools are often compared but they are not direct substitutes. Here is how they differ:

Helm vs kubectl

Helmkubectl
What it managesA named release (group of resources)Individual resources
TemplatingYes, Go templates with valuesNo, static YAML only
Upgrade trackingYes, numbered revisions with historyNo built-in tracking
Rollbackhelm rollback to any revisionManual: re-apply previous manifest
Best forFull application lifecycle managementInspecting, debugging, one-off applies

Most teams use both: Helm to manage deployments, kubectl to inspect what is running. See deploying containers with kubectl for the raw kubectl workflow.

Helm vs Kustomize

HelmKustomize
Templating approachGo templates with values substitutionPatching and overlays on base YAML
Package distributionChart repositories and tarballsGit-based, no packaging format
Release managementFull release history and rollbackNone built-in
Learning curveModerate, template syntax and chart structureLower, patches are plain YAML
Best forThird-party charts, multi-environment appsCustomising existing manifests per environment

Neither is universally better. Helm works well when you want to distribute or install packaged software. Kustomize works well when you want to apply environment-specific patches to manifests you already control.

Common beginner mistakes

  1. Following Helm v2 tutorials that mention Tiller. Helm v2 is long deprecated. Any tutorial that includes helm init or instructions to deploy Tiller is outdated. Helm v3 requires no server-side component.
  2. Using —set for every value override instead of a values file. The —set flag creates problems in CI/CD: the values are not documented or version-controlled. For more than two overrides, use a -f values.yaml file committed to your repository.
  3. Not running helm repo update before installing. Local repository indexes go stale. Without updating, you may install an outdated Chart version or fail to find a recently published one.
  4. Storing database passwords in values files committed to Git. Plain-text secrets in version control are a serious security risk. Use Kubernetes Secrets or an external secrets manager, and keep sensitive configuration separate from your Chart values.
  5. Uninstalling a release and losing its history. By default helm uninstall deletes the release history from the cluster. Without history, helm rollback is unavailable. Use helm uninstall —keep-history if you may need to reference or roll back the release later.
  6. Editing deployed resources directly with kubectl after a Helm install. If you modify a Helm-managed resource with kubectl edit or kubectl apply, Helm does not know about that change. The next helm upgrade will overwrite it. Make all changes through Helm values and upgrades.
Secrets in values files

Committing plaintext passwords or API keys into a values.yaml file is one of the most common Helm security mistakes. Even in a private repository, secrets in version control can leak through logs, CI output, or access control mistakes. Use Kubernetes Secrets or Google Secret Manager and reference them from your templates instead.

Frequently asked questions

What is Helm in Kubernetes?

Helm is a package manager for Kubernetes. It bundles Kubernetes YAML configuration (Deployments, Services, Ingress, Secrets, and so on) into a single versioned package called a Chart. You can install, upgrade, and roll back a whole application with one command, rather than managing every YAML file separately.

Is Helm specific to GKE?

No. Helm works with any Kubernetes cluster, including GKE, EKS, AKS, and self-managed clusters. GKE users benefit from Helm in the same way anyone else does: repeatable deployments, environment-specific configuration, and release history. The commands and chart format are identical across all providers.

What is the difference between a Chart and a Release?

A Chart is the package. It contains templates, default values, and metadata. A Release is a specific installed instance of a Chart on a cluster. You can install the same Chart multiple times under different release names, creating independent Releases. For example, you might install the PostgreSQL chart as both db-primary and db-replica in the same cluster.

Helm vs kubectl: what is the difference?

kubectl applies individual YAML manifests to a Kubernetes cluster, one file at a time. Helm manages a group of related resources as a single named release, with templating, versioning, and rollback built in. kubectl is lower-level and more direct; Helm adds lifecycle management on top. Most teams use both: Helm to manage deployments, kubectl to inspect and debug what is running.

Does Helm still use Tiller?

No. Tiller was a server-side component in Helm v2 that ran inside the cluster with broad permissions, creating significant security concerns. Helm v3, released in November 2019, removed Tiller entirely. Helm v3 runs client-side and stores release state as Kubernetes Secrets inside the cluster, using your kubeconfig credentials directly.

How do I preview what Helm will deploy before applying it?

Run helm template RELEASE_NAME CHART_PATH -f values.yaml to render all templates locally with your values substituted and print the resulting YAML to stdout without applying anything. Use helm lint ./chart-dir to validate the chart structure and template syntax. Both commands are safe to run at any time and make no changes to the cluster.

Last verified: 23 March 2026 Cloud services change frequently. Verify details against official documentation before making infrastructure decisions.