---
title: chezmoi
url: https://doc.liz6.com/en/tools/chezmoi
locale: en
area: tools
tags:
- tools
date: null
modified: 2026-07-16
description: Sync dotfiles across machines — but the real point is figuring out what belongs in there and what doesn't.
---

# chezmoi

[chezmoi](https://chezmoi.io) stores dotfiles in a git repository, `apply`s them on each machine, and supports template-based differences per system. There are plenty of tutorials online, but what I really want to discuss here is the boundary: **what should be managed by it, and what shouldn't.**

My criterion is: only include files that I write myself and need to keep consistent across machines. Currently, this includes cross-platform items: WezTerm's `~/.wezterm.lua`, Neovim configuration on Windows, Windows PowerShell profile, and AutoHotKey. I edit these on both machines, so maintaining consistency is valuable.

Conversely, I haven't included the bulk of my Linux desktop setup — [Hyprland, Quickshell](hyprland/01-overview.md), waybar — for two reasons. First, the volume is large (Quickshell alone is 70,000 lines). Second, since it updates with the upstream rice, I prefer to "follow upstream + make a few local changes" rather than pulling someone else's tens of thousands of lines of QML into my dotfiles repository as a burden. Also, anything containing secrets is excluded — those should be handled via environment variables or a separate `.gitignore`, and never committed to any repository history.

The remaining daily workflow is simple:

```bash
chezmoi edit ~/.wezterm.lua    # edit source
chezmoi diff                   # see what will change on apply
chezmoi apply                  # apply changes
chezmoi cd && git commit -a && git push
```

On a new machine, a single `chezmoi init --apply <repo>` pulls and sets everything up.

Two mechanisms are worth knowing; they are sufficient:

**Filename prefixes denote attributes** — chezmoi does not store metadata; instead, it encodes attributes into the source filename: `dot_foo` → `~/.foo`, `private_` → permission 600, `executable_` → add executable bit, `readonly_`, `encrypted_` (decrypts on apply using age/gpg), and scripts starting with `run_` execute during apply (`run_once_` runs only once, suitable for package installation/initialization). Just look at the filename to know what it will become.

**Templates handle machine-specific differences** — `*.tmpl` files use Go templates, which can read built-in variables like `.chezmoi.os` and `.chezmoi.hostname`, as well as values you define yourself in `.chezmoidata` or the config:

```gotmpl
{{ if eq .chezmoi.os "windows" }}
shell = "pwsh"
{{ else }}
shell = "zsh"
{{ end }}
```

The same source file produces different results when applied on Windows versus Linux — this is exactly why my cross-platform configurations (WezTerm, PowerShell, Neovim on Windows) can share a single source. `chezmoi diff` always lets me see clearly what the template will render before applying.

It’s sufficient and not complex — the complexity never lies in the tool, but in the discipline of "resisting the urge to throw everything into it."
