$linuxjunkies
>

Manage Dotfiles with chezmoi

Track, template, and encrypt your dotfiles with chezmoi — then restore any machine to your exact config in one command.

IntermediateUbuntuDebianFedoraArch9 min readUpdated June 7, 2026

Before you start

  • Git installed and configured with your name and email
  • A remote Git repository (GitHub, Gitea, etc.) if you want to sync across machines
  • age installed for encrypted secrets (optional but recommended)
  • Basic familiarity with editing dotfiles and working in a terminal

Dotfiles are the soul of a configured system — your shell aliases, editor settings, Git config, and more. Keeping them in sync across multiple machines without accidentally committing secrets is the real challenge. chezmoi solves this by treating your home directory as a managed state, supporting templates, and integrating with secret managers so sensitive values never land in your repo.

How chezmoi Works

chezmoi maintains a source directory (default ~/.local/share/chezmoi) that mirrors your home directory. Files there are prefixed and transformed before being written to their destination. When you run chezmoi apply, it reconciles the source state against your actual home directory, only touching what has changed.

Key concepts you'll use constantly:

  • Source state — files under ~/.local/share/chezmoi, possibly templated
  • Target state — the rendered result chezmoi wants your home directory to contain
  • Actual state — what's really on disk in your home directory

Installation

Install chezmoi from your distro's package manager. The upstream also ships a one-liner installer if your distro lags behind.

Debian / Ubuntu

sudo apt install chezmoi

Fedora / RHEL / Rocky

sudo dnf install chezmoi

Arch

sudo pacman -S chezmoi

Universal installer (any distro, always current)

sh -c "$(curl -fsLS get.chezmoi.io)" -- -b ~/.local/bin

Make sure ~/.local/bin is in your PATH if you use the universal installer.

Initialising Your Dotfile Repository

If you are starting fresh, run chezmoi init with no arguments. This creates the source directory and an empty Git repository inside it.

chezmoi init

If you already have a dotfiles repo on GitHub (or another host), pass the repository URL and chezmoi clones it into the source directory automatically:

chezmoi init https://github.com/youruser/dotfiles.git

Confirm the source directory path:

chezmoi source-path

Output will be something like /home/alice/.local/share/chezmoi.

Adding and Managing Files

Tell chezmoi to track a file with chezmoi add. It copies the file into the source directory with the correct prefix.

chezmoi add ~/.bashrc ~/.gitconfig ~/.config/nvim/init.lua

Edit the source copy directly (preferred):

chezmoi edit ~/.bashrc

Preview what apply would change before committing:

chezmoi diff

Apply the source state to your home directory:

chezmoi apply

After applying, commit the source directory to Git:

chezmoi cd
git add -A
git commit -m "add bashrc and gitconfig"
git push

Using Templates for Machine-Specific Config

Templates let the same source file render differently on different machines — your work laptop can get a different Git email than your personal one. chezmoi uses Go's text/template syntax.

Converting a file to a template

chezmoi add --template ~/.gitconfig

The source file is now named dot_gitconfig.tmpl. Open it:

chezmoi edit ~/.gitconfig

Replace static values with template variables pulled from chezmoi's data. chezmoi auto-populates data from ~/.config/chezmoi/chezmoi.toml.

Example dot_gitconfig.tmpl:

[user]
    name  = {{ .chezmoi.fullname }}
    email = {{ .email }}

Define .email and other custom variables in your config file:

cat ~/.config/chezmoi/chezmoi.toml
[data]
    email = "[email protected]"

You can also branch on the hostname or OS:

{{- if eq .chezmoi.hostname "work-laptop" }}
    email = "[email protected]"
{{- else }}
    email = "[email protected]"
{{- end }}

Run chezmoi apply to render the template and write the result to ~/.gitconfig. The template itself never lands in your home directory.

Keeping Secrets Out of the Repo

Secrets (API keys, tokens, passphrases) must never be stored in plain text in your dotfiles repo. chezmoi integrates natively with age (file encryption) and pass (the standard Unix password manager), among others.

Option A — Encrypting files with age

Install age and generate a key:

# Debian/Ubuntu
sudo apt install age

# Fedora
sudo dnf install age

# Arch
sudo pacman -S age
age-keygen -o ~/.config/chezmoi/key.txt
# Output: Public key: age1ql3z7hjy...

Tell chezmoi to use age and point it at the key and recipient (your public key):

cat ~/.config/chezmoi/chezmoi.toml
[encryption]
    tool = "age"
    age.identity = "~/.config/chezmoi/key.txt"
    age.recipient = "age1ql3z7hjy..."   # paste your public key here

Add a secret file — chezmoi encrypts it before writing to the source directory:

chezmoi add --encrypt ~/.ssh/id_ed25519

The source file becomes encrypted_dot_ssh/encrypted_private_id_ed25519.age. That encrypted blob is safe to commit. On apply, chezmoi decrypts it using your key file. Keep your key.txt out of the repo — back it up securely elsewhere.

Option B — Reading secrets from pass at template render time

If you use pass, reference secrets inline in templates:

export GITHUB_TOKEN={{ passFields "github/token" | get "password" }}

chezmoi calls pass when rendering the template, so the actual value is never stored in the source directory.

Bootstrapping a New Machine

This is where chezmoi pays off. On a brand-new system, a single command clones your repo, renders templates, decrypts secrets, and writes everything to the correct locations:

chezmoi init --apply https://github.com/youruser/dotfiles.git

If you want to review what will change before it touches anything:

chezmoi init https://github.com/youruser/dotfiles.git
chezmoi diff
chezmoi apply

For age-encrypted files, copy your key.txt to the new machine first (via encrypted USB, age-encrypted transfer, a secrets manager, etc.) before running apply.

Verification

Check that chezmoi's view of target state matches what's on disk:

chezmoi verify

If every managed file is up to date, the command exits silently with code 0. Any discrepancy is printed and exits non-zero — useful in CI or a post-login script.

See the managed file list:

chezmoi managed

Keeping Things Up to Date

Pull the latest commits from your remote and apply in one step:

chezmoi update

This is equivalent to git pull inside the source directory followed by chezmoi apply. Wire it into a systemd user timer or a shell login hook for fully automatic syncing if you prefer.

Troubleshooting

  • Template rendering errors — run chezmoi execute-template on a single template file to see the error in isolation: chezmoi execute-template < ~/.local/share/chezmoi/dot_gitconfig.tmpl
  • age decryption fails on a new machine — the most common cause is a missing or wrong key.txt. Confirm the path in chezmoi.toml matches where you copied the key. Double-check with age --decrypt -i ~/.config/chezmoi/key.txt somefile.age.
  • File shows as modified even after apply — this usually means the file has a different permission bit in the source. Use chezmoi diff to confirm, then re-add it with the correct mode: chezmoi add --mode 600 ~/.ssh/config.
  • chezmoi not found after universal install — add export PATH="$HOME/.local/bin:$PATH" to your ~/.bashrc or ~/.zshrc and reload.
tested on:Ubuntu 24.04Fedora 40Arch rollingDebian 12

Frequently asked questions

Does chezmoi overwrite files I edit directly in my home directory?
Only when you run 'chezmoi apply'. It will show you the diff first if you run 'chezmoi diff'. To pull changes from your home directory back into the source, use 'chezmoi re-add'.
Can I use chezmoi without a public Git host like GitHub?
Yes. The source directory is just a local Git repo. You can push to any Git server, a self-hosted Gitea instance, or keep it local-only with no remote at all.
Is my age private key safe if my dotfiles repo is public?
Yes, as long as you never add the private key file to the repo. Only the encrypted blobs and the public recipient key belong there. Back up key.txt out-of-band.
What is the difference between 'chezmoi apply' and 'chezmoi update'?
'apply' renders and writes the current source state to disk. 'update' first pulls the latest commits from the remote, then calls apply — it is the normal day-to-day sync command.
Can chezmoi run scripts when applying, for example to install packages?
Yes. Files prefixed with 'run_' or 'run_once_' in the source directory are executed as scripts during apply. This lets you automate package installs or post-copy hooks.

Related guides