Skip to main content

Template Directives

File-specific template options can be set using template directives. Directives are special comments in templates that configure how the template is processed.

Directive Syntax

Directives use the format:
chezmoi:template:$KEY=$VALUE
Where $KEY is the option name and $VALUE is its value. $VALUE must be quoted if it contains spaces or double quotes.

Multiple Directives

Multiple key/value pairs may be specified on a single line:
chezmoi:template:left-delimiter="[[" right-delimiter="]]"
If multiple directives are present in a file, later directives override earlier ones.

Removing Directives

Lines containing template directives are automatically removed to avoid parse errors from any delimiters. This means directives don’t appear in the final output.

Delimiters

By default, chezmoi uses the standard text/template delimiters {{ and }}. These can be changed per-file using the delimiter directive.

Syntax

chezmoi:template:left-delimiter=$LEFT right-delimiter=$RIGHT
Either or both of left-delimiter=$LEFT and right-delimiter=$RIGHT may be omitted. If either $LEFT or $RIGHT is empty, the default delimiter ({{ and }} respectively) is used instead.
Delimiters are specific to the file in which they appear and are not inherited by templates called from the file.

Examples

Shell Script with Custom Delimiters

script.sh.tmpl
#!/bin/bash
# chezmoi:template:left-delimiter="# [[" right-delimiter="]]"

echo "Hello, # [[ .chezmoi.username ]]!"

# [[ if eq .chezmoi.os "darwin" ]]
echo "Running on macOS"
# [[ else ]]
echo "Running on # [[ .chezmoi.os ]]"
# [[ end ]]

Docker Compose with Alternative Delimiters

docker-compose.yml.tmpl
# chezmoi:template:left-delimiter="<%" right-delimiter="%>"
version: '3'
services:
  app:
    image: myapp:<% .version %>
    environment:
      - USER=<% .chezmoi.username %>

Only Change Left Delimiter

chezmoi:template:left-delimiter="<<<"
# Uses <<< and }}
<<< .variable }}}

Encoding

Templates are always written in UTF-8 with no byte order mark. The output encoding can be transformed using the encoding directive.

Syntax

chezmoi:template:encoding=$ENCODING

Supported Encodings

EncodingDescription
utf-8UTF-8 with no byte order mark (default)
utf-8-bomUTF-8 with a byte order mark
utf-16-beBig-endian UTF-16 with no byte order mark
utf-16-be-bomBig-endian UTF-16 with a byte order mark
utf-16-leLittle-endian UTF-16 with no byte order mark
utf-16-le-bomLittle-endian UTF-16 with a byte order mark

Examples

UTF-16 Little-Endian Output

config.ini.tmpl
{{/* chezmoi:template:encoding=utf-16-le */}}
[settings]
value={{ .setting }}

UTF-8 with BOM

file.txt.tmpl
{{/* chezmoi:template:encoding=utf-8-bom */}}
Content goes here

Format Indent

By default, chezmoi’s toJson, toToml, and toYaml template functions use an indent of two spaces. This can be overridden per-file.

Syntax

Literal String Indent

chezmoi:template:format-indent=$STRING
Sets the indent to the literal $STRING.

Width-Based Indent

chezmoi:template:format-indent-width=$WIDTH
Sets the indent to $WIDTH spaces.

Examples

Tab Indentation

config.json.tmpl
{{/* chezmoi:template:format-indent="\t" */}}
{{ dict "key" "value" "nested" (dict "a" "b") | toJson }}
Output:
{
	"key": "value",
	"nested": {
		"a": "b"
	}
}

Four-Space Indentation

config.yaml.tmpl
{{/* chezmoi:template:format-indent-width=4 */}}
{{ dict "key" "value" "list" (list 1 2 3) | toYaml }}
Output:
key: value
list:
    - 1
    - 2
    - 3

Line Endings

Many template functions use UNIX-style line endings (lf/\n), which may cause unexpected output on Windows or when running chezmoi diff on modify_ templates. Line endings can be overridden with a directive.

Syntax

chezmoi:template:line-endings=$VALUE

Values

ValueEffect
lfUse UNIX-style line endings (\n)
crlfUse Windows line endings (\r\n)
nativeUse platform-native line endings (crlf on Windows, lf elsewhere)
Custom stringUse the literal string as line ending

Examples

Windows Line Endings

script.bat.tmpl
REM chezmoi:template:line-endings=crlf
@echo off
echo {{ .message }}

Platform-Native Line Endings

file.txt.tmpl
{{/* chezmoi:template:line-endings=native */}}
Line 1
Line 2

Force LF on Windows

script.sh.tmpl
# chezmoi:template:line-endings=lf
#!/bin/bash
echo "{{ .message }}"

Missing Keys

By default, chezmoi returns an error if a template indexes a map with a key that is not present. This behavior can be changed globally with the template.options configuration variable or per-file with a directive.

Syntax

chezmoi:template:missing-key=$VALUE

Values

ValueEffect
errorReturn an error on any missing key (default)
invalidIgnore missing keys. If printed, the result is <no value>
zeroIgnore missing keys. If printed, the result is the zero value

Examples

Ignore Missing Keys with Zero Values

config.tmpl
{{/* chezmoi:template:missing-key=zero */}}
username={{ .username }}
email={{ .email }}
optional={{ .optional_field }}
If .optional_field doesn’t exist, it outputs an empty string instead of erroring.

Show “no value” for Missing Keys

debug.tmpl
{{/* chezmoi:template:missing-key=invalid */}}
Debug info:
- required: {{ .required }}
- optional: {{ .optional }}
Output if .optional is missing:
Debug info:
- required: value
- optional: <no value>

Combining Directives

Multiple directives can be used in the same file:
script.ps1.tmpl
# chezmoi:template:left-delimiter="<%" right-delimiter="%>" line-endings=crlf encoding=utf-8-bom

Write-Host "Hello, <% .chezmoi.username %>!"

<% if eq .chezmoi.os "windows" %>
Write-Host "Running on Windows"
<% end %>

Directive Placement

Directives can appear anywhere in the file but should typically be placed:
  1. At the top of the file for visibility
  2. Inside comments appropriate for the file type
  3. Before the content they affect

Examples

Shell Script
#!/bin/bash
# chezmoi:template:left-delimiter="[[" right-delimiter="]]"
Go Template Comment
{{/* chezmoi:template:missing-key=zero */}}
YAML Comment
# chezmoi:template:format-indent-width=4
HTML Comment
<!-- chezmoi:template:encoding=utf-8-bom -->

Practical Examples

PowerShell Script

dot_profile.ps1.tmpl
# chezmoi:template:line-endings=crlf
# chezmoi:template:left-delimiter="<%" right-delimiter="%>"

$env:PATH += ";$HOME\\bin"

<% if .work %>
# Work configuration
$env:COMPANY_HOME = "<% .company_path %>"
<% end %>

Write-Host "Welcome, <% .chezmoi.username %>!"

JSON Configuration with Tabs

dot_config_app_settings.json.tmpl
{{/* chezmoi:template:format-indent="\t" */}}
{{
	dict 
		"theme" .theme
		"fontSize" .font_size
		"plugins" .plugins
	| toJson
}}

Windows Batch File

setup.bat.tmpl
REM chezmoi:template:line-endings=crlf encoding=utf-8-bom
@echo off
set USERNAME={{ .chezmoi.username }}
set INSTALL_DIR={{ .install_dir }}
echo Installing for %USERNAME%...

Modify Template with Matching Line Endings

modify_dot_bashrc.tmpl
# chezmoi:template:line-endings=native
# chezmoi:modify-template
{{ .chezmoi.stdin }}

# Added by chezmoi
export PATH="$HOME/.local/bin:$PATH"

Global vs. File-Specific Options

Global Configuration

~/.config/chezmoi/chezmoi.toml
[template]
    options = ["missingkey=zero"]
Applies to all templates.

File-Specific Override

specific-file.tmpl
{{/* chezmoi:template:missing-key=error */}}
Overrides the global setting for this file only.

Debugging Directives

Test directive behavior:
# Execute template with directives
chezmoi cat ~/.bashrc

# View the rendered template
chezmoi execute-template < template.tmpl

# Compare source and target
chezmoi diff

Build docs developers (and LLMs) love