Automating my computers setup with chezmoi

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:

BASH
sh -c "$(curl -fsLS get.chezmoi.io)"
chezmoi init
Click to expand and view more

The init command initializes chezmoi and creates the directory:

PLAINTEXT
~/.local/share/chezmoi
Click to expand and view more

This 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:

BASH
chezmoi add ~/.bashrc
Click to expand and view more

Chezmoi creates a copy of the file inside:

PLAINTEXT
~/.local/share/chezmoi/dot_bashrc
Click to expand and view more

From now on, you should edit the file via chezmoi:

BASH
chezmoi edit ~/.bashrc
Click to expand and view more

You can check differences with:

BASH
chezmoi diff
Click to expand and view more

And apply changes with:

BASH
chezmoi apply
Click to expand and view more

Simple and clean.


Version Control with Git

Now we want proper version control:

BASH
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 main
Click to expand and view more

Great…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:

TOML
[git]
    autoCommit = true
    autoPush = true
Click to expand and view more

Now 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:

BASH
{{ 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 }}
Click to expand and view more

The variable .machine you see above is defined in:

PLAINTEXT
~/.config/chezmoi/chezmoi.toml
Click to expand and view more

and it looks like this:

TOML
[data]
  machine = "personal" # set to "work" on work machines
Click to expand and view more

Clean 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

PLAINTEXT
run_once_<scriptname>
Click to expand and view more

Define a script that runs only once per machine.

Run when content changes

PLAINTEXT
run_onchange_<scriptname>
Click to expand and view more

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:

BASH
sh -c "$(curl -fsLS get.chezmoi.io)" -- init --apply <your-github-username>
Click to expand and view more

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:

BASH
sh -c "$(curl -fsLS get.chezmoi.io)" -- init https://git.example.com/<username>/<repo-name>.git
Click to expand and view more

That’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

Start searching

Enter keywords to search articles

↑↓
ESC
⌘K Shortcut