Helm cheatsheet.

Install

brew install helm

Repo

helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo list
helm repo update
helm search repo nginx
helm search hub redis

Install

helm install my-redis bitnami/redis
helm install my-redis bitnami/redis --version 19.5.0
helm install my-redis bitnami/redis -f values.yaml
helm install my-redis bitnami/redis --set auth.password=x --set replica.replicaCount=3
helm install my-redis bitnami/redis -n redis --create-namespace
helm install my-redis . --dry-run --debug         # local chart

Upgrade

helm upgrade my-redis bitnami/redis -f values.yaml
helm upgrade --install my-redis bitnami/redis      # upsert
helm upgrade my-redis bitnami/redis --atomic --timeout 5m
helm upgrade my-redis bitnami/redis --reuse-values --set replica.count=5

--atomic: rollback on failure.

List / inspect

helm list
helm list -A                          # all namespaces
helm status my-redis
helm get values my-redis
helm get values my-redis --all
helm get manifest my-redis            # rendered YAML
helm history my-redis

Rollback

helm rollback my-redis 2
helm rollback my-redis 2 --wait

Uninstall

helm uninstall my-redis
helm uninstall my-redis --keep-history

Create chart

helm create mychart

Creates:

mychart/
├── Chart.yaml
├── values.yaml
├── charts/
└── templates/
    ├── deployment.yaml
    ├── service.yaml
    ├── ingress.yaml
    ├── _helpers.tpl
    └── NOTES.txt

Chart.yaml

apiVersion: v2
name: mychart
version: 0.1.0
appVersion: "1.0.0"
description: My app
dependencies:
  - name: postgresql
    version: 14.x.x
    repository: https://charts.bitnami.com/bitnami
    condition: postgresql.enabled

values.yaml

replicaCount: 2
image:
  repository: nginx
  tag: "1.27"
  pullPolicy: IfNotPresent
service:
  type: ClusterIP
  port: 80
ingress:
  enabled: false
  hosts:
    - host: chart-example.local
      paths: ["/"]
resources:
  limits: { cpu: 500m, memory: 256Mi }
  requests: { cpu: 100m, memory: 128Mi }

Templates

# templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "mychart.fullname" . }}
  labels: {{- include "mychart.labels" . | nindent 4 }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels: {{- include "mychart.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      labels: {{- include "mychart.selectorLabels" . | nindent 8 }}
    spec:
      containers:
        - name: {{ .Chart.Name }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          resources: {{- toYaml .Values.resources | nindent 12 }}

Built-in objects

{{ .Release.Name }}            # release name
{{ .Release.Namespace }}
{{ .Chart.Name }}
{{ .Chart.Version }}
{{ .Chart.AppVersion }}
{{ .Values.image.tag }}
{{ .Files.Get "config.yaml" }} # file contents
{{ .Capabilities.KubeVersion.Major }}

Templating functions

{{ .Values.name | default "default" }}
{{ .Values.name | upper }}
{{ .Values.name | quote }}
{{ .Values.tag | toString }}
{{ .Values | toYaml | indent 4 }}
{{ range .Values.hosts }}
- host: {{ . }}
{{ end }}
{{ if .Values.enabled }}...{{ end }}
{{ with .Values.image }}{{ .repository }}:{{ .tag }}{{ end }}

Conditionals

{{- if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
...
{{- end }}

Lookup

{{ $secret := lookup "v1" "Secret" .Release.Namespace "my-secret" }}
{{- if $secret }}
existing: true
{{- end }}

Helpers (_helpers.tpl)

{{- define "mychart.labels" -}}
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}

Dependencies

helm dependency update
helm dependency build

In Chart.yaml:

dependencies:
  - name: postgresql
    version: 14.x.x
    repository: https://charts.bitnami.com/bitnami
    condition: postgresql.enabled
    alias: db
    import-values:
      - child: master.service
        parent: dbService

Subchart values in values.yaml:

postgresql:
  auth:
    password: secret

Test

helm lint .
helm template . | less                # render to stdout
helm install --dry-run --debug myrelease .

Package + publish

helm package .                        # creates mychart-0.1.0.tgz
helm push mychart-0.1.0.tgz oci://ghcr.io/me/charts

OCI registry support (no need for chartmuseum).

helmfile (multi-release)

brew install helmfile
# helmfile.yaml
releases:
  - name: ingress-nginx
    namespace: ingress-nginx
    chart: ingress-nginx/ingress-nginx
    values: [values/ingress-nginx.yaml]
  
  - name: my-app
    namespace: myapp
    chart: ./charts/myapp
    values: [values/myapp/${ENV:-dev}.yaml]
helmfile sync                         # apply all
helmfile diff
helmfile destroy

Common mistakes

  • Forgetting --namespace — wrong env.
  • Indent issues in templates — careful with nindent.
  • Hardcoded values in templates instead of values.yaml.
  • Not pinning chart version → broken upgrades.
  • Mixing helm + kubectl edits → drift.

Read this next

If you want my Helm chart template + helmfile setup, it’s at rajpoot.dev .


Building something AI-, backend-, or data-heavy and want a second pair of eyes? I do consulting and freelance work — see my projects and ways to reach me at rajpoot.dev .