Managing dotfiles with GNU Stow
Every developer has configuration files scattered across their home directory. Shell config, editor settings, tmux, git, terminal emulator. When you set up a new machine or reinstall your OS, recreating that environment from memory is painful. Dotfiles management solves this, and GNU Stow is the simplest tool for the job.
What Stow does
Stow creates symlinks. That is it. You organize your config files in a directory structure that mirrors where they belong in your home directory, and Stow creates the symlinks to put them in the right place.
dotfiles/
zsh/
.zshrc
.zprofile
nvim/
.config/
nvim/
init.lua
lua/
tmux/
.tmux.conf
git/
.gitconfig
Each top-level directory is a "package." Running stow zsh from the dotfiles directory creates a symlink from ~/.zshrc to dotfiles/zsh/.zshrc. Running stow nvim symlinks ~/.config/nvim/ to the right place.
Setting it up
Install Stow (it is in every package manager):
# Ubuntu/Debian
sudo apt install stow
# Arch
sudo pacman -S stow
# macOS
brew install stowCreate your dotfiles repo:
mkdir ~/dotfiles
cd ~/dotfiles
git initMove your existing configs into the structure. For example, for your zsh config:
mkdir -p ~/dotfiles/zsh
mv ~/.zshrc ~/dotfiles/zsh/.zshrc
cd ~/dotfiles
stow zshNow ~/.zshrc is a symlink pointing to ~/dotfiles/zsh/.zshrc. Edit either one and the changes apply everywhere.
Why not just symlinks?
You could create symlinks manually, but Stow handles the directory structure for you. If your Neovim config lives at ~/.config/nvim/init.lua, Stow creates the intermediate directories and symlinks correctly. Doing this by hand for 10+ configs is tedious and error-prone.
Stow also handles unstowing cleanly. stow -D zsh removes the symlinks without touching the files in your dotfiles repo.
The workflow
My daily workflow is simple:
- Edit a config file (the symlink means I edit it in place)
cd ~/dotfiles && git add -A && git commit -m "update zsh config"git push
On a new machine:
git clone git@github.com:username/dotfiles.git ~/dotfiles
cd ~/dotfiles
stow zsh nvim tmux git alacrittyFive commands and my entire environment is restored. The first time I did this on a fresh install and had everything working in under 5 minutes, I knew this was the right approach.
Handling conflicts
If a file already exists where Stow wants to create a symlink, it will refuse. You need to either delete or move the existing file first. I keep a small setup script in my dotfiles repo that handles common conflicts:
#!/bin/bash
# Remove defaults before stowing
rm -f ~/.zshrc ~/.gitconfig ~/.tmux.conf
cd ~/dotfiles
stow zsh git tmux nvim alacritty starshipWhat I track
My dotfiles repo includes configs for: Zsh, Neovim, tmux, Alacritty, Starship prompt, Git, and a few shell scripts I use daily. I do not track anything with secrets in it. API keys and tokens go in a .env file that is gitignored.
The repo is about 50 files and has saved me hours every time I set up a new machine or reinstall my OS. If you are not tracking your dotfiles yet, this is the weekend project with the highest return on investment.
Sources
Related posts
Why shadcn/ui changed how I build React interfaces
What makes shadcn/ui different from traditional component libraries, and why copying components into your project is actually the better approach.
pnpm workspaces: managing monorepos without the headache
A practical guide to using pnpm workspaces for monorepo management, with real patterns from actual projects.
Building a personal knowledge base with Obsidian
How I use Obsidian to organize notes, documentation, and ideas with linked thinking and plain Markdown files.
Enjoying the blog? Subscribe via RSS to get new posts in your reader.
Subscribe via RSS