In Lesson 1, you managed a file that's identical across machines. But most dotfiles aren't identical — your work laptop has different PATHs, your personal machine loads different tools. Templates let one source file render differently on each machine.
A template is a source file with placeholders. When chezmoi applies it, it fills in the placeholders with data from the current machine:
The same template produces different output on different machines because the data changes — not the template itself. This is the core mechanism that makes chezmoi useful for multi-machine setups.
Chezmoi uses Go's text/template package. Everything between {{ }} delimiters is a template action. Outside those delimiters, text passes through unchanged.
To insert a variable's value into the rendered file:
# Machine: {{ .chezmoi.hostname }}
On a machine named work-mbp, this renders as:
# Machine: work-mbp
The dot (.) is the root data object. Everything under .chezmoi is machine-detected data that chezmoi populates automatically.
Use {{ if }} / {{ end }} to include blocks conditionally:
{{ if eq .chezmoi.hostname "work-mbp" }}
export CORP_PROXY="http://proxy.corp.internal:8080"
{{ end }}
This line only appears in the rendered file on the machine named work-mbp. On all other machines, it's omitted entirely.
{{ if eq .chezmoi.os "darwin" }}
export BREW_PREFIX="/opt/homebrew"
{{ else }}
export BREW_PREFIX="/home/linuxbrew/.linuxbrew"
{{ end }}
Template actions introduce blank lines where the {{ }} blocks are. Use {{- }} and {{ -}} to trim surrounding whitespace:
{{- if eq .chezmoi.os "darwin" }}
export BREW_PREFIX="/opt/homebrew"
{{- end }}
The - trims the newline before or after the action, producing clean output without extra blank lines.
Run chezmoi data to see everything chezmoi knows about the current machine:
chezmoi data
This outputs JSON. The .chezmoi object contains auto-detected machine information. Here are the most useful fields:
| Template Variable | Example Value | Use Case |
|---|---|---|
.chezmoi.hostname | work-mbp | Per-machine config (proxy, paths) |
.chezmoi.os | darwin, linux | OS-specific tools and paths |
.chezmoi.arch | amd64, arm64 | Architecture-specific binaries |
.chezmoi.username | iforster | User-specific paths |
.chezmoi.homeDir | /Users/iforster | Cross-platform home directory |
.chezmoi.osRelease.id | ubuntu, fedora | Linux distro detection |
Run chezmoi data | jq '.chezmoi' to see just the machine-specific fields. This shows you exactly what variables are available for your templates.
Chezmoi distinguishes templates from static files by the .tmpl suffix in the source state:
| Source State File | Rendered Target |
|---|---|
dot_gitconfig | ~/.gitconfig (copied verbatim) |
dot_zshrc.tmpl | ~/.zshrc (rendered through template engine) |
Without .tmpl, chezmoi copies the file as-is. With .tmpl, it processes {{ }} actions before writing the target.
To convert an already-managed file to a template:
chezmoi chattr +template ~/.zshrc
This renames dot_zshrc to dot_zshrc.tmpl in the source state. You can also add a file as a template from the start:
chezmoi add --template ~/.zshrc
You'll convert your .zshrc (or .bashrc) to a template that sets machine-specific PATH entries.
chezmoi data | jq '.chezmoi.hostname'
Note the exact hostname string. You'll use this in your conditional.
chezmoi add --template ~/.zshrc
This creates dot_zshrc.tmpl in the source state with your current .zshrc content.
chezmoi edit ~/.zshrc
Add a conditional block. For example, if your work machine is named work-mbp and your personal machine is home-mac:
# Shared PATH
export PATH="$HOME/bin:$PATH"
{{- if eq .chezmoi.hostname "work-mbp" }}
# Work-specific tools
export PATH="/opt/corp-tools/bin:$PATH"
export KUBECONFIG="$HOME/.kube/work-config"
{{- else if eq .chezmoi.hostname "home-mac" }}
# Personal tools
export PATH="$HOME/.cargo/bin:$PATH"
export GOPATH="$HOME/go"
{{- end }}
chezmoi cat ~/.zshrc
This shows what the template renders to on this machine. Verify the correct branch was chosen.
chezmoi diff
chezmoi apply ~/.zshrc
Review the diff first. If it looks right, apply it. Your ~/.zshrc now contains only the machine-appropriate config.
chezmoi cd
git add .
git commit -m "feat: templatize .zshrc with hostname-based PATH"
git push
exit
If your template has a syntax error, chezmoi apply will refuse to write the file and show the error. Use chezmoi cat ~/.zshrc to test rendering before applying. You won't corrupt your actual file.
| Command | What it did |
|---|---|
chezmoi data | Showed all template variables for this machine |
chezmoi add --template <file> | Added a file as a template (with .tmpl suffix) |
chezmoi chattr +template <file> | Converted an existing managed file to a template |
chezmoi edit <file> | Opened the source state file in your editor |
chezmoi cat <file> | Rendered the template and printed the result (without applying) |
.tmpl suffix tell chezmoi?.tmpl suffix tells chezmoi to process {{ }} actions through Go's template engine before writing the rendered output to the target path..tmpl suffix means "this file is a template." Chezmoi processes all {{ }} actions through Go's template engine and writes the rendered result to the target. Without .tmpl, the file is copied verbatim..) accesses the root data object. All chezmoi-provided variables are nested under .chezmoi, so the full path is .chezmoi.os..) represents the root data context. Chezmoi nests its machine data under .chezmoi, so the correct access is {{ .chezmoi.os }}.chezmoi cat ~/.zshrc do?chezmoi cat renders the template as if it were being applied, but only prints the output — it never writes to the target. It's the safe way to preview what apply would produce.chezmoi cat renders the template with the current machine's data and prints the result to stdout. It doesn't modify any files — it's a safe preview of what apply would write.Machine-detected variables cover the basics, but what about data chezmoi can't auto-detect — like whether this machine is "work" vs "personal," or which cloud provider you use? In Lesson 3: Custom Data Files, you'll define your own variables in .chezmoidata.yaml and use them in templates.
chezmoi Templating Guide — The full reference for template syntax, functions, and available data. Covers everything from basic conditionals to advanced pipeline functions. ~10 minute read.