2026-08-21
Bob Glickstein wrote stow in 1996 to solve the /usr/local problem: how do you install a dozen packages from source without them colliding, and how do you uninstall one cleanly? His answer was so clean that thirty years of "modern" dotfile managers keep reinventing pieces of it, badly.
The idea: install each package into its own tree (/usr/local/stow/emacs-29.1/), then symlink everything back into /usr/local/. Uninstall = remove symlinks. Nothing overlaps. The killer application today isn't /usr/local — it's dotfiles.
Structure a git repo mirroring your home directory, one folder per package:
~/dotfiles/
├── vim/ .vimrc
├── zsh/ .zshrc, .zshenv
└── nvim/ .config/nvim/init.lua
Then:
cd ~/dotfiles
stow -t ~ vim zsh nvim
Stow creates ~/.vimrc → ~/dotfiles/vim/.vimrc, ~/.config/nvim/init.lua → ~/dotfiles/nvim/.config/nvim/init.lua, etc. New machine? Clone, stow, done.
The tricks nobody uses:
--adopt bootstraps from an existing home directory. Files already in ~ that match stow's tree get moved into the package and symlinked back:
mkdir -p ~/dotfiles/vim
mv ~/.vimrc ~/dotfiles/vim/ # or let --adopt do it
stow --adopt -t ~ vim
--dotfiles lets you commit dot-vimrc instead of .vimrc, so git tooling and your file manager stop hiding half the repo:
~/dotfiles/vim/dot-vimrc # → ~/.vimrc
stow --dotfiles vim
-n (simulate) plus -v is the dry-run every install script forgets to write:
stow -nv -t ~ vim
Tree folding is the genuinely magical part. If only vim/ has content under .config/nvim/, stow symlinks the directory: ~/.config/nvim → ~/dotfiles/vim/.config/nvim. Later, when you stow another package that puts a file inside .config/nvim/, stow silently unfolds: replaces the directory symlink with a real directory, symlinks the individual files. Refold happens automatically on -D. No mkdir-p ceremony, ever.
Per-host layering with two stow directories:
stow -d ~/dotfiles -t ~ base
stow -d ~/dotfiles-work -t ~ machine # overlays on top
Clean uninstall and reinstall:
stow -D -t ~ vim # remove every symlink stow created
stow -R -t ~ vim # restow (D then S) after renames
Why not just ln -s in a script? Because stow knows the tree structure. It refuses to clobber non-symlinks (unless --override), it folds and unfolds directories on demand, and — the part every homegrown script forgets — it knows exactly which symlinks it made, so -D is a real uninstall instead of a graveyard of orphaned links.
Why not a "modern" dotfile manager? Because stow is 3,400 lines of Perl 5 that ships on every distro, needs no config file, no daemon, no yaml, no init step. apt install stow, brew install stow, pacman -S stow. It has outlived four generations of Ruby/Go replacements and will outlive the next four.
stow command, one stow -D to undo — with directory folding that no hand-rolled symlink script will ever get right.
