Managing dotfiles across machines

Dotfiles are personal configuration files, usually stored under your home directory or ~/.config. Managing them across machines is a configuration management problem: keep useful…

Dotfiles are personal configuration files, usually stored under your home directory or ~/.config. Managing them across machines is a configuration management problem: keep useful settings reproducible, keep secrets out of the repository, and make machine-specific differences explicit.

Decide what belongs in dotfiles

Track configuration you would want to rebuild on a new machine: shell settings, editor configuration, Git configuration, terminal settings and tool defaults.

Do not track private keys, access tokens, browser profiles, caches, build outputs or generated files. Treat public dotfiles repositories as public documentation. Anything committed there should be safe to publish.

Separate personal preferences from project policy. Repository-level files such as .editorconfig, formatter settings and CI scripts belong with the project, not in personal dotfiles.

Use a repository as the source of truth

A Git repository gives you history, review and rollback. Keep the layout predictable. One common pattern is to mirror the target home directory structure inside the repository.

dotfiles/
  git/
    .gitconfig
  shell/
    .bashrc
  editor/
    .config/editor/config

This layout works well with symlink managers such as GNU Stow, because each package can contain files laid out as they should appear under the target directory.

Use GNU Stow for simple symlink management

GNU Stow is a symlink farm manager. It takes separate package directories and makes them appear under a target directory by creating symbolic links.

With a repository like this:

dotfiles/
  git/
    .gitconfig
  shell/
    .bashrc

Run Stow from the repository and target the home directory.

cd ~/dotfiles
stow --target="$HOME" git shell

The files in ~/dotfiles/git and ~/dotfiles/shell then appear in the home directory through symbolic links.

Stow is a good fit when machines can share mostly the same files and you want minimal tooling. Its main constraint is that the repository layout and the target layout are tightly connected.

Use chezmoi when machines differ

chezmoi manages dotfiles by storing the desired state and applying it to each machine. It offers features beyond symlinking, including templates and machine-specific configuration.

A typical workflow starts by adding an existing file, editing the source state, then applying it.

chezmoi add ~/.gitconfig
chezmoi edit ~/.gitconfig
chezmoi apply

chezmoi is a good fit when laptops, servers and workstations need different values in the same logical file. Templates can express those differences without maintaining entirely separate copies.

Use templates sparingly. A simple copied file is easier to inspect than a template with many branches.

Keep secrets out of plain text

Never commit private SSH keys, API tokens or production credentials. Use a password manager, secret manager or an encrypted workflow designed for secrets.

For dotfiles, prefer references to secret material rather than the secret itself. For example, configure a tool to read a token from an environment variable or credential helper.

export TOOL_CONFIG="$HOME/.config/tool/config"

Audit before pushing. Use Git status, Git diff and secret scanning where available.

git status --short
git diff --cached

Handle machine-specific differences explicitly

Do not rely on accidental hostnames or manual edits that are never committed. Record differences in a clear place.

Common patterns include:

  • separate packages, such as work, personal and server
  • templates that branch on operating system or hostname
  • small local include files that are intentionally ignored by Git

For shell configuration, keep local overrides isolated.

# In .bashrc
if [ -f "$HOME/.bashrc.local" ]; then
  . "$HOME/.bashrc.local"
fi

Then ignore the local file.

.bashrc.local

This keeps the shared file stable while allowing a machine to carry private or temporary settings.

Make bootstrap boring

A new machine should need only a short, documented bootstrap path. Keep the first run safe and repeatable.

git clone https://example.com/dotfiles.git ~/dotfiles
cd ~/dotfiles
stow --target="$HOME" shell git

For chezmoi, use its init and apply workflow.

chezmoi init https://example.com/dotfiles.git
chezmoi apply

Do not let bootstrap scripts install large amounts of software without confirmation. Configuration restore and package installation are related, but they have different failure modes.

Review changes before applying them

Dotfile changes can break login shells, editors and Git authentication. Review generated changes before applying them, especially on a remote host.

git diff
stow --no --verbose --target="$HOME" shell
chezmoi diff

A dry run is valuable because dotfiles usually affect the interactive recovery tools you depend on. Breaking an editor is inconvenient. Breaking a shell startup file on a remote server can be worse.

Keep configuration portable, not identical

The goal is repeatability, not forcing every machine to be the same. A workstation, a laptop and a server have different roles. Dotfile tooling should make shared defaults easy and local differences obvious.

Prefer small files, comments for non-obvious choices and documented bootstrap commands. Remove old settings when the tool they configure is no longer used.

Conclusion

Good dotfile management is simple configuration management. Put safe, useful settings in version control, keep secrets out, choose Stow for straightforward symlink workflows and choose chezmoi when machines need templated differences. The best setup is the one you can review before applying and rebuild without relying on memory.