What's the best dotfiles manager?
The best dotfiles manager depends on what you're actually managing. Search best dotfiles manager and you land in the same conversation every time: a Reddit thread, a Hacker News comment section, an awesome-dotfiles list with thirty entries. The top reply is always some version of "it depends," and the thread never converges because the question hides two different jobs under one word.
"Dotfiles" can mean the files in your home directory, the ~/.gitconfig and ~/.config/nvim you want identical on every machine. Or it can mean a configured machine, the files plus the packages those files configure, the services, and the repositories you clone before you can do any work. A tool that is best at the first job is usually not even trying to do the second. So before picking a tool, answer the question the threads skip: which job are you actually doing?
50/50
Why the threads never agree, half the people in any "best dotfiles manager" thread want to sync a handful of config files across two laptops. The other half want a new machine to be ready after one command. They recommend different tools, both are right, and the disagreement is invisible because they all typed the same word.
Sort the tools by scope and the noise clears up. There are file managers, and there are machine provisioners. Most of the popular names are firmly in the first group.
File managers
If syncing files in $HOME is genuinely all you need, this is the field. The file managers, from minimal to full-featured:
- GNU Stow a symlink farm and nothing more. You keep files in a repo,
stowlinks them into place. Minimal, universal, perfect for a dozen files. It breaks the moment a real file already exists where a link should go. - dotbot Stow plus a config file. The same symlinking with a declarative
install.conf.yamlso the layout is described, not scripted. - dotdrop dotbot with templating and grouping. One source renders per-machine variants through Jinja, with a following for grouping files by machine without duplicating them. Heavier config in exchange for the cross-machine logic.
- bare git repo no tool at all, a git work-tree checked out directly over
$HOME. Clever, dependency-free, and unforgiving the first time yougit statusin the wrong directory. - yadm git in
$HOMEwith batteries: per-machine alternates, a bootstrap hook, basic encryption. A real step up if you already think in git. - chezmoi the most capable file manager by a distance. A single Go binary, real templating, age encryption, and password-manager integration. If files in
$HOMEare the whole job, this is the one to beat.
Notice these are not really competing on capability for the file job so much as on taste: how much magic you want between the repo and the file. Pick the least powerful one that covers your files and stop there.
Machine managers
Run down what a file manager does not do, and the same gap appears in all of them:
- install the packages those config files configure (apt, Homebrew, a language toolchain)
- set system state (services,
sysctl,wsl.conf, locale) - clone the repositories you need before the machine is useful
- keep all of that idempotent, so a re-run repairs drift instead of redoing work
Every tool in the list above answers these the same way: a run_ script, a bootstrap hook, an install.sh you maintain by hand. chezmoi is honest about this, its own design FAQ draws the line and points past "a handful of files" at "Puppet, Chef, Ansible, and Salt." The file manager handles the files, and a second, imperative tool handles everything around them. Now you maintain two things that drift apart.
The "ready after one command" crowd is reaching for a different category. Nix home-manager is the popular answer here: declarative, reproducible, with real rollback, at the cost of a genuine learning curve and its own language. The heavyweight configuration managers (Salt, Puppet, Chef) can do it too, but they are built for servers and feel like it on a laptop.
This is the half of the field the dotfiles threads usually forget exists, which is exactly why those threads never settle.
File + machine manager
Ansible already turns up in these threads, but usually in its weakest form: a role that clones the dotfiles repo and sets up symlinks. That works, and it also leaves the best part of the tool on the table, because symlinking files is the one thing Ansible does no better than Stow. The point of reaching for a configuration manager is everything a symlink cannot do.
Dotfiles Pro is that provisioner, and it has not forgotten the files. It is an Ansible collection that manages the whole developer machine, packages, system config, repositories, and dotfiles, for one laptop or a fleet, from one repo:
- One tool for the whole machine. No symlink manager plus a separate
setup.sh. Packages and config apply in the same idempotent run. - Settings, not files. Roles write only the keys you declare, so a software update keeps its improved defaults instead of fighting a whole file you froze years ago. See why a role beats a symlink for the long version.
- Idempotent and incremental. Re-run anytime, target one role with
--tags, preview with--diff. Install and update are the same code path. - Scales from one laptop to a fleet. The same layout serves a personal machine and a twenty-person team sharing a baseline.
What that looks like in practice: one command bootstraps a machine from your dotfiles repo.
curl -LsSf https://dotfiles.pro/install.sh | sh -s -- git@gitlab.com:yourname/mydotfiles.gitThe playbook it runs is short, and a single apply installs the packages, writes your settings, and clones your repos. The vars are the point, git_config writes only the keys you name into ~/.gitconfig rather than owning the whole file, and git_repositories clones what the machine needs:
roles:
# OS base: the matching one runs, the other is skipped (facts decide)
- role: dotfilespro.roles.ubuntu
when: ansible_facts.os_family == 'Debian'
- role: dotfilespro.roles.macos
when: ansible_facts.os_family == 'Darwin'
- dotfilespro.roles.git
- dotfilespro.roles.docker
- dotfilespro.roles.dotpro
vars:
git_config:
user:
name: Your Name
email: you@example.com
git_repositories:
.dotfiles: git@gitlab.com:yourname/mydotfiles.gitdocker is the package, the git identity is the configured dotfile, the repositories are cloned, all in one idempotent run you repeat on the next machine with the same command.
The honest trade is that it is not a single static binary, you run Ansible, and it targets Ubuntu, macOS, and WSL rather than every distribution. If a one-file download on any OS is your hard requirement, a file manager wins on that axis.
Conclusion
The recommendation follows the scope, not the brand:
- Only files in
$HOME, on your own machines? Use chezmoi. It is simpler and it is excellent. Stow or a bare repo if even chezmoi is more than you want. - Reproducibility and rollback above all, and you'll learn a language for it? Nix.
- Packages, system state, repositories, and dotfiles managed together, on Ubuntu, macOS, or WSL, solo or as a team? That is the gap Dotfiles Pro is built for.
And it is not always either-or. You can keep the file manager you already like and add a machine layer beside it: chezmoi for the files, Dotfiles Pro for the machine in a dotpro/ subdir, or keep your raw dotfiles repo where Stow still works and layer provisioning on top.
For the scored, feature-by-feature tables across all of these, with migration paths in and out, see the alternatives comparison. The best dotfiles manager is the least powerful tool that covers your actual scope. The only mistake is answering the question before you have figured out which scope you are in.