Graphic showing the Helm logo on a purple background

Helm is a package manager for Kubernetes workloads. Creating a Helm chart for your application simplifies reproducible deployments into a Kubernetes cluster. Users can install the whole chart with one command, instead of manually applying individual component manifests with Kubectl.

In this article, we’ll show you how to get started with Helm by writing a chart for a simple application. A “chart” is conceptually similar to a “package” of Kubernetes manifests which Helm lets you manage as a single entity.

What’s a Helm Chart?

Helm charts apply the familiar model of package management encountered in operating systems and programming languages to applications running in a Kubernetes cluster. A Helm chart can have dependencies and children; all these components are automatically started in your cluster when you install a top-level chart.

Charts are fully versioned using a semantic release strategy. Similarly to an npm module or OS package, you can pin charts to specific versions and track their changes over time. This simplifies rolling back application deployments to a known good release should you run into issues in your cluster.

Helm charts also incorporate templating capabilities for supplying dynamic values at installation time. You can configure new applications without directly editing their manifest files, using variables that are provided by the chart developer.

Installing Helm

Helm’s distributed as a plain binary via the project’s GitHub Releases page. Download the correct distribution for your system, make it executable, and move it into a location within your PATH.

Helm’s also present in the package repositories of most popular Linux distributions. You can find it in Homebrew for macOS and Chocolatey and Scoop for Windows too.

Once installation’s complete, run helm version to check everything’s working:

$ helm version  --template='Version: {{.Version}}'
Version: v3.8.1

Helm commands target your active Kubernetes cluster connection as used by Kubectl. Your selected Kubeconfig file and context will be used for all Helm commands. You can reference a different config file with the standard KUBECONFIG environment variable or --kubeconfig flag mechanisms.

Creating a Helm Chart

Now you can begin creating a Helm chart for your application. Use the helm create command to scaffold a new chart in your working directory:

$ helm create my-app-chart

The chart’s content will be deposited inside the my-app-chart directory. Let’s inspect what it contains:

$ ls my-app-chart
Chart.yaml  charts  templates   values.yaml

There are two top-level files and two supplementary sub-directories. Here’s what each resource is used for:

  • Chart.yaml – Your Helm chart’s manifest defining metadata properties including its name and version.
  • values.yaml – This file stores default values for variables that you can reference in your chart. It’s possible to override values that are set here using CLI flags when you install the chart.
  • templates – The templates directory contains your chart’s Kubernetes object manifests. Installing the chart will apply all these manifests to your cluster. Any valid Kubernetes YAML manifest can be placed here; you can also use extra functionality, such as references to variables defined in your values.yaml file. We’ll look at this capability below.
  • charts – The charts directory holds other Helm charts which this one depends on. It’s used to configure complex parent-child chart relationships. We won’t be covering this feature in this article so you can delete the directory if you don’t need it.

Helm’s default chart comes pre-configured to deploy an instance of the NGINX web server. The Kubernetes manifests in the templates directory create the various constituent components, such as a Deployment, Service, and Ingress. The application is configured by variables defined in values.yaml; here you’ll find settings for the image tag, service port, and Ingress host, among others:

$ cat values.yaml
# Default values for my-app-chart.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.

replicaCount: 1

  repository: nginx
  pullPolicy: IfNotPresent
  # Overrides the image tag whose default is the chart appVersion.
  tag: ""

Installing the Chart

To add the application to your cluster, use the helm install command:

$ helm install my-app .
NAME: foo
LAST DEPLOYED: Tue Mar 29 14:47:48 2022
NAMESPACE: default
STATUS: deployed

The first argument to the command defines the name of your release. The second argument references the directory path to load the Helm chart from. You can use . when your working directory is already set to the root of your chart.

You’ll receive some terminal output that describes the installed release. The NOTES section consists of information provided by the chart.

To override values.yaml variables, provide one or more instances of the --set flag:

$ helm install my-app . --set replicaCount=3 --set image.tag=1.20

This example would deploy three replicas of a container running the nginx:1.20 image. You can check this by listing the Pods in your cluster using Kubectl:

$ kubectl get pods
NAME                                   READY   STATUS    RESTARTS   AGE
my-app-my-app-chart-6d6577749c-2qbhb   1/1     Running   0          61s
my-app-my-app-chart-6d6577749c-wdmgv   1/1     Running   0          44s
my-app-my-app-chart-6d6577749c-x5wp7   1/1     Running   0          40s

Upgrading, Retrieving, and Deleting Chart Releases

Next make some changes to the chart or alter a variable’s value:

$ helm install my-app . --set replicaCount=5
Error: INSTALLATION FAILED: cannot re-use a name that is still in use

Repeating the install command doesn’t work. To apply changes to a chart that’s already deployed, use the upgrade command instead. This creates a new “release” inside the cluster.

$ helm upgrade my-app . --set replicaCount=5
Release "my-app" has been upgraded. Happy Helming!

You can list all the deployed chart releases in your cluster with helm list:

$ helm list
NAME    NAMESPACE   REVISION    UPDATED                                 STATUS      CHART               APP VERSION
my-app  default     2           2022-03-30 15:09:34.370758719 +0100 BST deployed    my-app-chart-0.1.0  1.16.0

Each release’s details includes its name, the number of times it’s been deployed, its last update time, and the version numbers of the chart and the application it provides.

To remove a release and destroy its Kubernetes objects, pass its name to the uninstall command:

$ helm uninstall my-app
release "my-app" uninstalled

Writing Your Own Chart From Scratch

Now let’s see how to write a basic chart from scratch. Create a new directory for your chart; we’re calling ours cloudsavvy-chart. Add a Chart.yaml file inside with the following content:

apiVersion: v2
name: cloudsavvy-chart
description: An example Helm chart.
type: application
version: 0.1.0
appVersion: 1.1.0

The type field should usually be set to application. The other supported type is library. Library charts package functionality that can be included as a dependency of other charts. They don’t contain any Kubernetes templates themselves.

The version field refers to the version of your chart. You should increment this each time you modify the chart’s templates. appVersion indicates the version of the primary software component your chart provides. It signals to chart users what will be running in their cluster after they install the chart. As an example, if you’re creating a chart that distributes WordPress, it would be appropriate to set appVersion to the WordPress version number you’re providing.

Next create a values.yaml file with a few simple variables:

deploymentName: cloudsavvy
image: nginx:latest
replicas: 1

These variables will be referenced in your chart template. Add this template now as templates/deployment.yaml. Our basic chart will deploy a single Pod so it’ll only have one template file. In a real-world situation, it’s good practice to create individual manifest files for each of your application’s components.

apiVersion: apps/v1
kind: Deployment
  name: {{ .Values.deploymentName }}-deployment
      app: {{ .Values.deploymentName }}
  replicas: {{ .Values.replicas }}
        app: {{ .Values.deploymentName }}
        - name: {{ .Values.deploymentName }}
          image: {{ .Values.image }}

The Deployment uses values from values.yaml to configure the image reference and replica count. The deploymentName variable is used throughout so that any future changes can be made in one place. Fields in values.yaml are referenced using the {{ .Values.FIELD_NAME }} syntax.

Now use Helm to install the chart:

$ helm install cloudsavvy-app . --set replicas=3
NAME: cloudsavvy-app
LAST DEPLOYED: Tue Mar 29 15:43:21 2022
NAMESPACE: default
STATUS: deployed

The --set flag overrides the default value of replicas that’s set in values.yaml. After the overrides have been applied, Helm injects the resolved values into the correct places in your YAML templates. The final Kubernetes manifests are then applied to your cluster. You can now verify that three containers are running by using Kubectl to list your cluster’s Pods.

$ kubectl get pods
NAME                                     READY   STATUS              RESTARTS   AGE
cloudsavvy-deployment-7b975bd985-5r7dc   0/1     ContainerCreating   0          15s
cloudsavvy-deployment-7b975bd985-bpbkm   0/1     ContainerCreating   0          15s
cloudsavvy-deployment-7b975bd985-jzb5q   0/1     ContainerCreating   0          15s


Helm charts let you package collections of Kubernetes manifests as complete applications that are ready to deploy. You can create templated configurations that end users can easily change before installing a release into a cluster.

In this guide, we’ve explained the basics of Helm’s functionality and shown how you can create your own simple charts for your applications. We’ve barely covered the surface of what Helm can achieve though – once you’ve written a chart, you can push it to a repository for others to use, add other charts as dependencies, and build more advanced charts using functions, pipelines, and control flow expressions. Taking the time to learn Helm makes your Kubernetes deployments more flexible, powerful, and reusable.

Profile Photo for James Walker James Walker
James Walker is a contributor to How-To Geek DevOps. He is the founder of Heron Web, a UK-based digital agency providing bespoke software development services to SMEs. He has experience managing complete end-to-end web development workflows, using technologies including Linux, GitLab, Docker, and Kubernetes.
Read Full Bio »