Helm Syntax Teamplate



indent and nindent

🔹 1. indent Function

Usage:

{{ indent N "your string" }}


  • Adds N spaces at the beginning of each line in the given string.

  • Does not add a newline before the string.

  • Commonly used when you need to shift a block of text to the right.

✅ Example:

{{ indent N "your string" }}


Output:

    line1
    line2
    line3



🔹 2. nindent Function (newline + indent)

Usage:

{{ nindent N "your string" }}


  • Same as indent, but also adds a newline before the indented string.

  • Very useful when you're inserting a block of content inside YAML structure, and need to start on a new line with proper indentation.

✅ Example:

env:
{{- nindent 2 "- name: ENV_VAR\n  value: \"123\"" }}


Output:

env:
  - name: ENV_VAR
    value: "123"


Without nindent, the YAML would be invalid because the list item would not be properly indented under env:.


🆚 Summary: indent vs nindent

Function

Adds Indentation?

Adds Newline Before?

Use Case

indent

✅ Yes

❌ No

Indenting already-newlined string

nindent

✅ Yes

✅ Yes

Start block on new line with proper indenting


🔁 Common Use in Helm Templates

spec:
  containers:
    - name: myapp
      env:
{{- .Values.env | toYaml | nindent 8 }}


  • toYaml converts map/list to YAML

  • nindent 8 indents it under env: correctly with 8 spaces

Purpose of {{- and -}} in Helm Templates

These are used to control whitespace (spaces, tabs, newlines) in your rendered YAML files.

🔹 Syntax Variants:

Syntax

Meaning

{{ ... }}

Default – preserves whitespace

{{- ... }}

Trims whitespace before the tag

{{ ... -}}

Trims whitespace after the tag

{{- ... -}}

Trims whitespace before and after the tag


📌 Why is this important in Helm?

Helm templates output YAML, which is indent-sensitive. Uncontrolled whitespace can result in:

  • ❌ Invalid YAML

  • ❌ Unwanted blank lines

  • ❌ Bad formatting


✅ Example: No Trimming


env:
{{ toYaml .Values.env | indent 2 }}


If .Values.env is:


- name: FOO
  value: bar


Then the rendered output might look like:


env:


- name: FOO
  value: bar


❗Note the extra blank line between env: and the list.


✅ Example: Trimming with {{- and -}}


env:
{{- toYaml .Values.env | indent 2 }}


Now Helm trims the newline before the toYaml, and you get:


env:
  - name: FOO
    value: bar


🎯 Clean YAML. No unwanted lines.


🔁 Practical Rule of Thumb

Use Case

Use {{- or -}}?

Avoid extra blank lines

{{- before or -}} after

Start block right after a field (like env:)

Use {{-

End block without trailing newline

Use -}}

Maintain readability (when formatting doesn't matter)

Avoid trimming


👇 Real Example in a Helm Template

yaml

CopyEdit

apiVersion: v1
kind: ConfigMap
metadata:
  name: myconfig
data:
{{- range $key, $val := .Values.config }}
  {{ $key }}: {{ $val | quote }}
{{- end }}


✅ This ensures:

  • No blank line before or after the loop

  • Proper YAML alignment

In Helm, .Files is a built-in object that allows you to access, read, and manipulate files inside your chart’s files/ directory at template rendering time.


🔍 .Files – What It Is

  • .Files refers to the set of all non-template files stored in the files/ directory of a Helm chart.

  • These are not deployed directly as standalone Kubernetes resources, but are accessible programmatically from your templates.


🧩 Typical Use Cases

  1. Load a config file into a ConfigMap

  2. Inject scripts, certs, or binary blobs into pods

  3. Read YAML or JSON and parse as dict

  4. Base64 encode content for Secrets


📁 Example Chart Structure

mychart/
├── templates/
│   └── configmap.yaml
├── files/
│   ├── myconfig.yaml
│   └── script.sh



📘 Common .Files Functions

Function

Purpose

.Files.Get "path"

Returns string content of the file

.Files.GetBytes "path"

Returns raw bytes of the file

.Files.Glob "pattern"

Returns a map of matched files by glob

.Files.AsSecrets

Converts files to secrets (base64-encoded)

.Files.AsConfig

Converts files to plain text ConfigMap


✅ Examples

1. Load File Content into ConfigMap

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  myconfig.yaml: |-
{{ .Files.Get "myconfig.yaml" | indent 4 }}


2. Base64 Encode for Secret

apiVersion: v1
kind: Secret
metadata:
  name: my-secret
type: Opaque
data:
  script.sh: {{ .Files.Get "script.sh" | b64enc }}


3. Iterate Over Multiple Files Using Glob

{{- $files := .Files.Glob "scripts/*.sh" }}
{{- range $path, $file := $files }}
# {{$path}}
{{ $file | indent 2 }}
{{- end }}



⚠️ Important Notes

  • Files must reside inside the files/ directory to be accessible via .Files.

  • You cannot access files from templates/, charts/, or outside the chart root.

  • .Files.Get returns an empty string if the file is not found—no error is thrown.


🧠 Summary

Feature

.Files is used for...

Dynamic Config

Injecting full file contents as config

Secret Data

Base64-encoding binary or text data

Scripts/Certs

Embedding scripts, TLS certs, etc.

Flexibility

Supporting user-custom files in charts


 complete working Helm chart example using .Files to load a config file into a ConfigMap and a shell script into a Secret.


📁 Helm Chart Structure (Example)

mychart/
├── Chart.yaml
├── values.yaml
├── templates/
│   ├── configmap.yaml
│   └── secret.yaml
├── files/
│   ├── myconfig.yaml
│   └── startup.sh



🔹 1. files/myconfig.yaml

app:
  name: my-app
  port: 8080



🔹 2. files/startup.sh

#!/bin/bash
echo "Starting application..."



🔹 3. templates/configmap.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: myconfigmap
data:
  myconfig.yaml: |-
{{ .Files.Get "myconfig.yaml" | indent 4 }}


✅ This loads files/myconfig.yaml content into the ConfigMap.


🔹 4. templates/secret.yaml

apiVersion: v1
kind: Secret
metadata:
  name: mysecret
type: Opaque
data:
  startup.sh: {{ .Files.Get "startup.sh" | b64enc }}


✅ This encodes files/startup.sh in Base64 and stores it in a Secret.


🔹 5. values.yaml

This chart doesn’t require values for .Files, but you can add values for naming or conditional loading if you want.

# Example of optional enhancements

configFile: myconfig.yaml
scriptFile: startup.sh



🔹 Optional Enhancement: Make .Files File Name Configurable

Modify configmap.yaml

{{- $cfg := .Values.configFile | default "myconfig.yaml" }}
apiVersion: v1
kind: ConfigMap
metadata:
  name: dynamic-configmap
data:
  {{ $cfg }}: |-
{{ .Files.Get $cfg | indent 4 }}



✅ How to Install and Test

helm install mychart ./mychart


Then check:

kubectl get configmap myconfigmap -o yaml
kubectl get secret mysecret -o yaml

In Helm templates, if, else if, and else blocks allow you to add conditional logic to dynamically render Kubernetes YAML based on the values you pass in values.yaml. Helm templates use Go templating syntax.


🔰 1. Beginner Level: Basic if and else

📌 Syntax:

{{- if CONDITION }}
  # block executed if condition is true
{{- else }}
  # block executed if condition is false
{{- end }}


✅ Example: Enable a config only if a feature flag is true

values.yaml:

featureEnabled: true


configmap.yaml:

apiVersion: v1
kind: ConfigMap
metadata:
  name: my-config
data:
{{- if .Values.featureEnabled }}
  feature: "enabled"
{{- else }}
  feature: "disabled"
{{- end }}


🧾 Explanation:

If .Values.featureEnabled is true, it outputs:

feature: "enabled"


Else:

feature: "disabled"



🔁 2. Intermediate Level: else if and nested logic

📌 Syntax:

{{- if CONDITION1 }}
  # do something
{{- else if CONDITION2 }}
  # do something else
{{- else }}
  # fallback
{{- end }}


✅ Example: Set logging level based on user choice

values.yaml:

logLevel: "debug"


configmap.yaml:

apiVersion: v1
kind: ConfigMap
metadata:
  name: log-config
data:
{{- if eq .Values.logLevel "debug" }}
  level: "DEBUG"
{{- else if eq .Values.logLevel "info" }}
  level: "INFO"
{{- else }}
  level: "ERROR"
{{- end }}


🧾 Explanation:

  • You check multiple conditions using else if and Go's eq function.

  • eq .Values.logLevel "debug" returns true if the logLevel is "debug".


🔄 3. Advanced Level: Checking empty values, lists, maps, and nested structures


🔍 A. Check if a value exists or is not empty

values.yaml:

optionalSetting: ""


configmap.yaml:

{{- if .Values.optionalSetting }}
  setting: {{ .Values.optionalSetting | quote }}
{{- else }}
  setting: "default"
{{- end }}


🧾 Explanation:

  • Helm treats empty strings, zero, false, and nil as "false".

  • So if optionalSetting is empty, the else branch is used.


📚 B. Check if a list has items

values.yaml:

allowedUsers:
  - alice
  - bob


configmap.yaml:

{{- if .Values.allowedUsers }}
users:
{{- range .Values.allowedUsers }}
  - {{ . }}
{{- end }}
{{- else }}
users: []
{{- end }}


🧾 Explanation:

  • If allowedUsers is not empty, it loops and prints them.

  • Else, it returns an empty list.


🔐 C. Nested if for complex structures

values.yaml:

auth:
  enabled: true
  method: "ldap"


configmap.yaml:

{{- if .Values.auth.enabled }}
auth:
  enabled: true
{{- if eq .Values.auth.method "ldap" }}
  type: "ldap"
{{- else }}
  type: "other"
{{- end }}
{{- else }}
auth:
  enabled: false
{{- end }}


🧾 Explanation:

  • First, you check if auth.enabled is true.

  • Then, based on auth.method, decide the type.


✅ Summary Table

Use Case

Helm Syntax Example

Basic condition

{{- if .Values.enabled }} ... {{- end }}

else handling

{{- if ... }} ... {{- else }} ... {{- end }}

else if

{{- else if eq .Values.mode "prod" }}

Empty string or list check

{{- if .Values.list }}

Nested conditions

Use {{- if }} inside another {{- if }}

Function-based checks

eq, ne, gt, lt, and, or etc.


🧠 Tips

  • Always close your if blocks with {{- end }}.

  • Use {{- (note the dash) to trim whitespace for clean YAML.

Use quote and default for safety:


setting: {{ .Values.setting | default "foo" | quote }}


  • Nesting too deep? Refactor using define and template.


Let's now dive deep into using logical operators like and, or, and not with if, else if, and else in Helm templates, from beginner to advanced.


🚦 Logical Operators in Helm (if conditions)

Helm templates are powered by Go templates, and they support logical operators like:

Operator

Meaning

and

Logical AND

or

Logical OR

not

Logical NOT

eq

Equal to

ne

Not equal to

lt

Less than

gt

Greater than

le

Less than or equal

ge

Greater than or equal


🧱 1. Basic Usage of and and or

✅ Example: and

values.yaml:

enableFeature: true
isProduction: true


deployment.yaml:

{{- if (and .Values.enableFeature .Values.isProduction) }}
# Only rendered if BOTH are true
annotations:
  feature: "enabled"
{{- else }}
# Either is false
annotations:
  feature: "disabled"
{{- end }}


🧾 Explanation:

  • and returns true only if all conditions are true.


✅ Example: or

values.yaml:

enableBeta: false
enablePreview: true


deployment.yaml:

{{- if (or .Values.enableBeta .Values.enablePreview) }}
# Render beta feature config
betaFeature: "active"
{{- else }}
betaFeature: "inactive"
{{- end }}


🧾 Explanation:

  • or returns true if any one condition is true.


🔂 2. not with if

values.yaml:

isTest: false


deployment.yaml:

{{- if (not .Values.isTest) }}
# Render this only in non-test environments
env: "production"
{{- else }}
env: "test"
{{- end }}



🔁 3. Combine Multiple Conditions (and, or, eq)

✅ Advanced Example: Multiple logic combinations

values.yaml:

env: "prod"
enableFeature: true
userRole: "admin"


configmap.yaml:

{{- if (and (eq .Values.env "prod") (eq .Values.userRole "admin") .Values.enableFeature) }}
accessLevel: "full"
{{- else }}
accessLevel: "limited"
{{- end }}


🧾 Explanation:

  • Checks all 3:

    • env is "prod"

    • userRole is "admin"

    • enableFeature is true


💡 Nesting and, or, not (Complex Conditions)

Example:

{{- if (or (and (eq .Values.env "prod") .Values.enableFeature) (eq .Values.env "staging")) }}
someFlag: true
{{- else }}
someFlag: false
{{- end }}


🧾 This renders someFlag: true if:

  • env is "prod" AND feature is enabled

  • OR env is "staging"


🔐 Condition on Map Key Existence (Advanced)

Sometimes you want to conditionally check if a key in a map exists and is not empty:

{{- if (and (hasKey .Values "auth") .Values.auth.enabled) }}
authEnabled: true
{{- else }}
authEnabled: false
{{- end }}



✅ Summary Table: Logical Operators with if

Use Case

Example

Basic AND

{{ if (and A B) }}

Basic OR

{{ if (or A B) }}

Basic NOT

{{ if (not A) }}

Combined with eq

{{ if (and (eq .Values.env "prod") .Values.enabled) }}

Grouped or and and

{{ if (or (and A B) C) }}

Key existence and condition

{{ if (and (hasKey .Values "foo") .Values.foo.bar) }}


🛠 Real-World Use Case: Toggle ingress

values.yaml:

ingress:
  enabled: true
  className: "nginx"


ingress.yaml:

{{- if (and .Values.ingress.enabled (eq .Values.ingress.className "nginx")) }}
# Create nginx ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx-route
spec:
  ingressClassName: nginx
{{- end }}

haskey



The hasKey function in Helm templates (inherited from Go templates) is used to check whether a map contains a specific key.


🔍 Purpose of hasKey

  • To safely check if a key exists in a map before trying to access it.

  • Prevents errors like:
    error calling include: can't evaluate field <key> in type <nil>


📘 Syntax

{{ hasKey MAP KEY }}


  • MAP: A map-like object (e.g., .Values, .Values.someMap)

  • KEY: A string or variable representing the key

🔁 It returns:

  • true → if the map contains the key

  • false → if the key is missing


✅ Simple Example

values.yaml

features:
  logging: true


configmap.yaml

{{- if (hasKey .Values.features "logging") }}
loggingEnabled: {{ .Values.features.logging }}
{{- else }}
loggingEnabled: false
{{- end }}


🧾 Explanation:

  • Checks if .Values.features map has the key "logging"

  • Only then tries to access .Values.features.logging


⚠️ Why hasKey is Important?

❌ Wrong:

{{- if .Values.config.enabled }}
# Error if `.Values.config` doesn't exist!
{{- end }}


✅ Correct:

{{- if (and (hasKey .Values "config") .Values.config.enabled) }}
# Safe check
{{- end }}



🧪 Example with Nested Maps

values.yaml

auth:
  methods:
    ldap: true


Template:

{{- if (and (hasKey .Values.auth "methods") (hasKey .Values.auth.methods "ldap")) }}
ldapEnabled: {{ .Values.auth.methods.ldap }}
{{- else }}
ldapEnabled: false
{{- end }}



🔁 Dynamic Key Check (with variables)

{{- $key := "database" }}
{{- if (hasKey .Values.services $key) }}
dbService: {{ .Values.services.database }}
{{- end }}



🔐 hasKey with required for Validation

{{ required "Missing config!" (hasKey .Values "config") }}


This ensures that the chart fails fast with a useful error if a key is missing.


⚡ Recap: When to Use hasKey

Scenario

Use hasKey?

Example

Accessing a key inside .Values

hasKey .Values "config"

Accessing deeply nested map keys

hasKey .Values.config "enabled"

Working with default values instead

Use default pipe: `{{ .Values.foo


🧠 Bonus Tip

For safety:

{{- if (and (hasKey .Values "myMap") (hasKey .Values.myMap "key1")) }}
  value: {{ .Values.myMap.key1 }}
{{- end }}




Distributed by Gooyaabi Templates | Designed by OddThemes