# Templating

Helmfile uses [Go templates](https://godoc.org/text/template) for templating your helmfile.yaml. While go ships several built-in functions, we have added all of the functions in the [Sprig library](https://godoc.org/github.com/Masterminds/sprig).

We also added the following functions:

* [`env`](templating_funcs.md#env)
* [`requiredEnv`](templating_funcs.md#requiredenv)
* [`exec`](templating_funcs.md#exec)
* [`envExec`](templating_funcs.md#envexec)
* [`readFile`](templating_funcs.md#readfile)
* [`readDir`](templating_funcs.md#readdir)
* [`readDirEntries`](templating_funcs.md#readdirentries)
* [`toYaml`](templating_funcs.md#toyaml)
* [`fromYaml`](templating_funcs.md#fromyaml)
* [`setValueAtPath`](templating_funcs.md#setvalueatpath)
* [`get`](templating_funcs.md#get) (Sprig's original `get` is available as `sprigGet`)
* [`getOrNil`](templating_funcs.md#getornil)
* [`tpl`](templating_funcs.md#tpl)
* [`required`](templating_funcs.md#required)
* [`fetchSecretValue`](templating_funcs.md#fetchsecretvalue)
* [`expandSecretRefs`](templating_funcs.md#expandsecretrefs)
* [`include`](templating_funcs.md#include)

More details on each function can be found at the ["Template Functions" page in our documentation](templating_funcs.md).

## Using environment variables

Environment variables can be used in most places for templating the helmfile. Currently this is supported for `name`, `namespace`, `value` (in set), `values` and `url` (in repositories).

Examples:

```yaml
repositories:
- name: your-private-git-repo-hosted-charts
  url: https://{{ requiredEnv "GITHUB_TOKEN"}}@raw.githubusercontent.com/kmzfs/helm-repo-in-github/master/
```

```yaml
releases:
  - name: {{ requiredEnv "NAME" }}-vault
    namespace: {{ requiredEnv "NAME" }}
    chart: roboll/vault-secret-manager
    values:
      - db:
          username: {{ requiredEnv "DB_USERNAME" }}
          password: {{ requiredEnv "DB_PASSWORD" }}
    set:
      - name: proxy.domain
        value: {{ requiredEnv "PLATFORM_ID" }}.my-domain.com
      - name: proxy.scheme
        value: {{ env "SCHEME" | default "https" }}
```

### Note

If you wish to treat your enviroment variables as strings always, even if they are boolean or numeric values you can use `{{ env "ENV_NAME" | quote }}` or `"{{ env "ENV_NAME" }}"`. These approaches also work with `requiredEnv`.

### Useful internal Helmfile environment variables

Helmfile uses some OS environment variables to override default behaviour:

* `HELMFILE_DISABLE_INSECURE_FEATURES` - disable insecure features, expecting `true` lower case
* `HELMFILE_DISABLE_RUNNER_UNIQUE_ID` - disable unique logging ID, expecting any non-empty value
* `HELMFILE_SKIP_INSECURE_TEMPLATE_FUNCTIONS` - disable insecure template functions, expecting `true` lower case
* `HELMFILE_USE_HELM_STATUS_TO_CHECK_RELEASE_EXISTENCE` - expecting non-empty value to use `helm status` to check release existence, instead of `helm list` which is the default behaviour
* `HELMFILE_EXPERIMENTAL` - enable experimental features, expecting `true` lower case
* `HELMFILE_ENVIRONMENT` - specify [Helmfile environment](environments.md), it has lower priority than CLI argument `--environment`
* `HELMFILE_KUBE_CONTEXT` - specify the kubectl context, it has lower priority than CLI argument `--kube-context`
* `HELMFILE_NAMESPACE` - specify the namespace, it has lower priority than CLI argument `--namespace`
* `HELMFILE_HELM_BINARY` - specify the path to the helm binary, it has lower priority than CLI argument `--helm-binary`
* `HELMFILE_KUSTOMIZE_BINARY` - specify the path to the kustomize binary, it has lower priority than CLI argument `--kustomize-binary`
* `HELMFILE_LOG_LEVEL` - specify the log level, it has lower priority than CLI argument `--log-level`
* `HELMFILE_DEBUG` - enable debug output, expecting `true` lower case. The same as `--debug` CLI flag
* `HELMFILE_QUIET` - silence output (equivalent to log-level warn), expecting `true` lower case. The same as `--quiet`/`-q` CLI flag
* `HELMFILE_NO_COLOR` - disable colored output, expecting `true` lower case. The same as `--no-color` CLI flag. `NO_COLOR` (any non-empty value, per [no-color.org](https://no-color.org/)) is also honored
* `HELMFILE_TEMPDIR` - specify directory to store temporary files
* `HELMFILE_UPGRADE_NOTICE_DISABLED` - expecting any non-empty value to skip the check for the latest version of Helmfile in [helmfile version](cli.md#version)
* `HELMFILE_GO_YAML_V3` - use *go.yaml.in/yaml/v3* instead of *go.yaml.in/yaml/v2*.  It's `false` by default in Helmfile v0.x, and `true` in Helmfile v1.x.
* `HELMFILE_CACHE_HOME` - specify directory to store cached files for remote operations
* `HELMFILE_FILE_PATH` - specify the path to the helmfile.yaml file
* `HELMFILE_INTERACTIVE` - enable interactive mode, expecting `true` lower case. The same as `--interactive` CLI flag
* `HELMFILE_RENDER_YAML` - force helmfile.yaml to be rendered as a Go template regardless of file extension, expecting `true` lower case. Useful for migrating from v0 to v1 without renaming files to `.gotmpl`
* `HELMFILE_AWS_SDK_LOG_LEVEL` - configure AWS SDK logging level for vals library. Valid values: `off` (default, secure, case-insensitive), `minimal`, `standard`, `verbose`, or custom comma-separated values like `request,response`. See issue #2270 for details
* `HELMFILE_VALS_FAIL_ON_MISSING_KEY_IN_MAP` - enable strict mode for vals secret references. When set to `true` (or any value accepted by Go's `strconv.ParseBool` like `TRUE`, `1`), vals will fail when a referenced key does not exist in the secret map. Invalid values will cause an error when vals is initialized (when secret refs are first evaluated). Default is `false` (when unset or empty) for backward compatibility. See issue #1563 for details


## Templates

You can use go's text/template expressions in `helmfile.yaml` and `values.yaml.gotmpl` (templated helm values files). `values.yaml` references will be used verbatim. In other words:

* for value files ending with `.gotmpl`, template expressions will be rendered
* for plain value files (ending in `.yaml`), content will be used as-is

In addition to built-in ones, the following custom template functions are available:

* `readFile` reads the specified local file and generate a golang string
* `readDir` reads the files within provided directory path. (folders are excluded)
* `readDirEntries` Returns a list of [https://pkg.go.dev/os#DirEntry](DirEntry) within provided directory path
* `fromYaml` reads a golang string and generates a map
* `setValueAtPath PATH NEW_VALUE` traverses a golang map, replaces the value at the PATH with NEW_VALUE
* `toYaml` marshals a map into a string
* `get` returns the value of the specified key if present in the `.Values` object, otherwise will return the default value defined in the function

### Values Files Templates

You can reference a template of values file in your `helmfile.yaml` like below:

```yaml
releases:
- name: myapp
  chart: mychart
  values:
  - values.yaml.gotmpl
```

Every values file whose file extension is `.gotmpl` is considered as a template file.

Suppose `values.yaml.gotmpl` was something like:

```yaml
{{ readFile "values.yaml" | fromYaml | setValueAtPath "foo.bar" "FOO_BAR" | toYaml }}
```

And `values.yaml` was:

```yaml
foo:
  bar: ""
```

The resulting, temporary values.yaml that is generated from `values.yaml.gotmpl` would become:

```yaml
foo:
  # Notice `setValueAtPath "foo.bar" "FOO_BAR"` in the template above
  bar: FOO_BAR
```

## Refactoring `helmfile.yaml` with values files templates

One of expected use-cases of values files templates is to keep `helmfile.yaml` small and concise.

See the example `helmfile.yaml` below:

```yaml
releases:
  - name: {{ requiredEnv "NAME" }}-vault
    namespace: {{ requiredEnv "NAME" }}
    chart: roboll/vault-secret-manager
    values:
      - db:
          username: {{ requiredEnv "DB_USERNAME" }}
          password: {{ requiredEnv "DB_PASSWORD" }}
    set:
      - name: proxy.domain
        value: {{ requiredEnv "PLATFORM_ID" }}.my-domain.com
      - name: proxy.scheme
        value: {{ env "SCHEME" | default "https" }}
```

The `values` and `set` sections of the config file can be separated out into a template:

`helmfile.yaml`:

```yaml
releases:
  - name: {{ requiredEnv "NAME" }}-vault
    namespace: {{ requiredEnv "NAME" }}
    chart: roboll/vault-secret-manager
    values:
    - values.yaml.gotmpl
```

`values.yaml.gotmpl`:

```yaml
db:
  username: {{ requiredEnv "DB_USERNAME" }}
  password: {{ requiredEnv "DB_PASSWORD" }}
proxy:
  domain: {{ requiredEnv "PLATFORM_ID" }}.my-domain.com
  scheme: {{ env "SCHEME" | default "https" }}
```

## Importing values from any source

The `exec` template function that is available in `values.yaml.gotmpl` is useful for importing values from any source
that is accessible by running a command:

A usual usage of `exec` would look like this:

```yaml
mysetting: |
{{ exec "./mycmd" (list "arg1" "arg2" "--flag1") | indent 2 }}
```

Or even with a pipeline:

```yaml
mysetting: |
{{ yourinput | exec "./mycmd-consume-stdin" (list "arg1" "arg2") | indent 2 }}
```

The possibility is endless. Try importing values from your golang app, bash script, jsonnet, or anything!

Then `envExec` same as `exec`, but it can receive a dict as the envs.

A usual usage of `envExec` would look like this:

```yaml
mysetting: |
{{ envExec (dict "envkey" "envValue") "./mycmd" (list "arg1" "arg2" "--flag1") | indent 2 }}
```

## Using .env files

Helmfile itself doesn't have an ability to load .env files. But you can write some bash script to achieve the goal:

```console
set -a; . .env; set +a; helmfile sync
```

Please see #203 for more context.

## Running Helmfile interactively

`helmfile --interactive [apply|destroy|delete|sync]` requests confirmation from you before actually modifying your cluster.

Use it when you're running `helmfile` manually on your local machine or a kind of secure administrative hosts.

For your local use-case, aliasing it like `alias hi='helmfile --interactive'` would be convenient.

Another way to use it is to set the environment variable `HELMFILE_INTERACTIVE=true` to enable the interactive mode by default.
Anything other than `true` will disable the interactive mode. The precedence has the `--interactive` flag.

## Running Helmfile without an Internet connection

Once you download all required charts into your machine, you can run `helmfile sync --skip-deps` to deploy your apps.
With the `--skip-deps` option, you can skip running "helm repo update" and "helm dependency build".

## `bash` and `zsh` completion

helmfile completion --help
