Setting up a new development machine is never complicated, but it’s always annoying.
Until recently, I relied on a bunch of custom bash scripts plus a few manual steps to configure my environment. My setup isn’t particularly complex and I don’t rebuild my machines very often, so that approach worked but I still felt it could be improved, without moving to something more “complex” like Ansible. I was looking for an easy enough machine-setup tool.
Reinstalling an OS - whether because of hardware changes, experiments gone wrong or just routine cleanup - always means reinstalling tools, restoring dotfiles and reapplying configuration tweaks. It’s not difficult, but it’s error prone, time consuming and repetitive. And repetitive tasks are exactly what we should automate.
So I started looking for a better solution. After some research, I found a tool that not only manages dotfiles cleanly, but also allows me to execute my existing setup scripts automatically.
The tool is chezmoi: https://www.chezmoi.io
Why Chezmoi?
There are many dotfile managers out there, but what I like most about chezmoi is:
- Native Git integration (with proper version control)
- Support for multiple machine configurations via templating
- Built-in script execution
- Conditional execution (run once, run only if changed, etc.)
- Support for secrets and password manager integrations
It feels lightweight, but powerful enough for real-world usage.
Installing Chezmoi
First, install it on a machine you’re already using:
sh -c "$(curl -fsLS get.chezmoi.io)"
chezmoi initThe init command initializes chezmoi and creates the directory:
~/.local/share/chezmoiThis is a version-controlled source directory that contains the managed versions of your configuration files. From this point forward, this source directory becomes the source of truth, while your home directory contains the rendered and managed files.
Adding Files to Chezmoi
Let’s say you want to manage your .bashrc:
chezmoi add ~/.bashrcChezmoi creates a copy of the file inside:
~/.local/share/chezmoi/dot_bashrcFrom now on, you should edit the file via chezmoi:
chezmoi edit ~/.bashrcYou can check differences with:
chezmoi diffAnd apply changes with:
chezmoi applySimple and clean.
Version Control with Git
Now we want proper version control:
chezmoi cd
git add .
git commit -m "Initial commit - adding bashrc"
git remote add origin git@<your-git-server.com>:<your-user>/dotfiles.git
git branch -M main
git push -u origin mainGreat…but there’s one issue.
If pushing changes requires manual action, sooner or later you’ll forget it (or at least I will forget it, I’m sure 😄). It’s like a manual backup… if it’s manual, it’s not really a backup anymore.
Luckily, chezmoi can auto-commit and auto-push changes.
Edit the file ~/.config/chezmoi/chezmoi.toml, adding:
[git]
autoCommit = true
autoPush = trueNow every edit done through chezmoi automatically commits and pushes to your repository.
That’s the kind of automation I like.
Handling Work vs Personal Machines
Before using chezmoi, I already had custom bash scripts to install the software I need. Now I wanted those scripts to behave differently depending on the machine.
For example:
- on work machines: Slack and VSCode
- in personal machines: VSCodium and DevPod (this could be a story for another blog post 😄)
With chezmoi templating, this is easy to achieve:
{{ if eq .machine "work" }}
flatpak list | grep -q com.visualstudio.code || flatpak install -y flathub com.visualstudio.code
flatpak list | grep -q com.slack.Slack || flatpak install -y flathub com.slack.Slack
{{ end }}
{{ if eq .machine "personal" }}
flatpak list | grep -q com.vscodium.codium || flatpak install -y flathub com.vscodium.codium
flatpak list | grep -q sh.loft.devpod || flatpak install -y flathub sh.loft.devpod
{{ end }}The variable .machine you see above is defined in:
~/.config/chezmoi/chezmoi.tomland it looks like this:
[data]
machine = "personal" # set to "work" on work machinesClean and flexible.
Running Scripts Only Once
Now comes an important question: how do we make sure setup scripts don’t run every time we execute chezmoi apply?
Chezmoi provides two useful prefixes for our scripts names, which will be located also in ~/.local/share/chezmoi/:
Run only once
run_once_<scriptname>Define a script that runs only once per machine.
Run when content changes
run_onchange_<scriptname>Define a script which runs the first time and again only if its content changes. Chezmoi tracks this using a stored hash of file content.
This makes your setup idempotent without writing complex logic yourself.
Managing Secrets
Need to set up SSH keys or manage sensitive data?
Chezmoi supports:
- Integration with password managers (1Password, Bitwarden, etc.) or
- Built-in file encryption
There’s a lot more to explore here: https://www.chezmoi.io/user-guide/encryption/
Bootstrapping a New Machine
Once your dotfiles repository is ready, setting up a new machine becomes trivial.
If you use GitHub and your repo is named dotfiles:
sh -c "$(curl -fsLS get.chezmoi.io)" -- init --apply <your-github-username>This will download chezmoi, will clone your public repo and will configure automatically your computer.
If you use a different Git server you can execute:
sh -c "$(curl -fsLS get.chezmoi.io)" -- init https://git.example.com/<username>/<repo-name>.gitThat’s it. One command, full environment!
Handling Pre-Apply Requirements
If you use a password manager to store your sensitive data used in chezmoi files, you may need it installed before running chezmoi apply, but after chezmoi init.
Chezmoi handles this via hooks.
For example, the hooks.read-source-state.pre hook allows you to modify your system after the repository is cloned but before chezmoi computes and reads the desired state from the source directory..
This gives you full control over bootstrap logic, because in this way you can run a script to download, setup and unlock your password manager before you run chezmoi apply command.
Final Thoughts
Chezmoi turned out to be much more than a dotfile manager. It became a lightweight configuration management layer for my personal machines.
It allows me to:
- Track every configuration change
- Version everything properly (and securely, in my self-hosted git server)
- Reproduce my setup reliably and easily
- Handle work and personal environments cleanly
- Bootstrap a new system in minutes
Is it a full replacement for tools like Ansible? No, not at all, but this is not its aim.
But to manage the setup of personal computers, it hits a very sweet spot between simplicity and power.
I’m currently hosting my chezmoi-managed dotfiles on a private self-hosted Forgejo instance, so I don’t have a public repository to share with you. However, GitHub is full of excellent examples if you want inspiration.
If you enjoy automating your environment and reducing friction when rebuilding machines, I definitely recommend giving chezmoi a try.
Happy hacking, Emanuel
Note
I know some of you will say: “Just use NixOS for a fully reproducible system.”
I actually tried it for about a month. It’s powerful, no doubt, but it’s also a completely different way of managing a system. My feeling was that when something breaks, you first have to understand how NixOS models it before you can solve the actual issue. I guess that’s just a skill issue on my side, so my fault! 😄
For now, I prefer solutions that work across any Linux distribution without changing the entire paradigm.
