Managing dotfiles with GNU Stow
May 09, 2026 •I used to have config files scattered all over my home directory — .zshrc here, .gitconfig there, random stuff in .config/. No version control, no single source of truth. The real pain hit when I'd tweak something on my MacBook Pro, then have to remember to do the same dance on the Mac Mini and my WSL workstation. Three machines, three copies of the same mess, zero sync. It was a nightmare. Then I found GNU Stow, and it changed everything.
Stow is a symlink farm manager. Fancy name, simple idea: you keep all your dotfiles in one tidy folder (~/dotfiles), and Stow creates symlinks from your home directory pointing back to it. Your configs stay organized, Git-trackable, and portable across machines.
The best part? You can enable or disable entire app configs with a single command.
Install it quick:
# Debian/Ubuntu
sudo apt install stow
# macOS
brew install stow
The workflow in 30 seconds
- Create
~/dotfiles - Make a subdirectory (a "package") for each app
- Move your config files into the matching directory structure
- Run
stow <package>from inside~/dotfiles
That's it. Let me show you what this looks like in practice.
Stowing .zshrc
ZSH config lives at ~/.zshrc. Here's the move:
cd ~/dotfiles
# Move your existing config in
mv ~/.zshrc .
# Stow it
stow zsh
Stow creates a symlink: ~/.zshrc → ~/dotfiles/.zshrc. You edit the file in either location — it's the same file.
Got more ZSH files? Throw them in:
mv ~/.zsh_aliases .
mv ~/.zsh_functions .
stow -R # Restow to pick up new files
Your package now looks like:
~/dotfiles/
├── .zshrc
├── .zsh_aliases
└── .zsh_functions
Stowing OpenCode
Editors like OpenCode keep config under ~/.config/opencode/. The key here is mirroring the directory structure inside your package:
cd ~/dotfiles
mkdir -p opencode/.config/opencode
mv ~/.config/opencode/* opencode/.config/opencode/
stow opencode
Now ~/.config/opencode is a symlink pointing into your dotfiles. Your settings, keybindings — all tracked:
~/dotfiles/
└── .config/
└── opencode/
├── opencode.jsonc
├── package.json
└── skills
Same pattern works for any app that stores config under ~/.config/ — Yazi, Newsboat, whatever you use. Create the package, mirror the path, stow it.
Version control with Git
This is where Stow really earns its keep. Your entire ~/dotfiles folder is just a regular directory — perfect for Git.
cd ~/dotfiles
git init
git add .
git commit -m "init"
git remote add origin [email protected]:rvibek/dotfiles.git
git push -u origin main
Add a .gitignore to keep things clean:
.DS_Store
*.swp
*~
*.db
*.lock
Day-to-day, the flow is dead simple — edit a config, commit, push:
git add zsh/.zshrc
git commit -m "Update zsh aliases"
git push
Setting up a new machine
This is the killer feature. Fresh system? Five commands:
brew install stow
git clone [email protected]:rvibek/dotfiles.git ~/dotfiles
cd ~/dotfiles
stow zsh opencode
Done. Your entire environment is back. And you can be selective — only stow what you need on that particular machine.
Commands worth remembering
stow <pkg>— create symlinksstow -D <pkg>— remove symlinksstow -R <pkg>— restow (useful after adding files)stow -n -v <pkg>— dry run, see what would happenstow */— stow every package at once
Quick troubleshooting
"Cannot stow over existing file" — a real file is in the way. Move it into your package first, then restow:
mv ~/.zshrc ~/dotfiles/zsh/
stow -R zsh
Happy stowing. ✌️