All posts
EngineeringJun 9, 20263 min read

Manage Your Dotfiles with GNU Stow

Stop copying config files by hand. GNU Stow creates symlinks from a single git-tracked directory — one command, no scripts, no hassle.

I was thinking about tracking my dotfiles for a few days. After exploring how others track their configs, I came across GNU Stow. It lets you manage configuration files across machines using symlinks — without writing a single custom script.

Instead of manually copying dotfiles between machines, I keep them in a single git repository (~/dotfiles) and use Stow to symlink everything into place.

The concept

Stow relies on a simple directory tree. You create a stow directory (~/dotfiles), and inside it you create subdirectories for each package (e.g., bash, vim, tmux). When you run stow, it mirrors every file under the package directory into the parent of the stow directory (typically $HOME).

# Example directory structure:
# ~/dotfiles/
# ├── zsh/
# │   └── .zshrc
# ├── tmux/
# │   └── .tmux.conf
# └── nvim/
#     └── .config/
#         └── nvim/
 
# After running `stow .` from ~/dotfiles:
# ~/
# ├── .zshrc         -> ~/dotfiles/zsh/.zshrc
# ├── .tmux.conf     -> ~/dotfiles/tmux/.tmux.conf
# └── .config/
#     └── nvim/      -> ~/dotfiles/nvim/.config/nvim/

Stow always maps the content of the stow directory to the target directory (defaults to the parent of the stow directory). Combine this with a clean git repo and you never lose a config again.

Basic usage

# Create your central dotfiles directory
mkdir ~/dotfiles
 
# Create a package directory for bash
mkdir ~/dotfiles/bash
 
# Move your existing .bashrc into the package directory
mv ~/.bashrc ~/dotfiles/bash/
 
# Navigate into the stow directory and symlink the package
cd ~/dotfiles
stow bash
 
# Now ~/.bashrc is a symlink pointing to ~/dotfiles/bash/.bashrc!

If you are running from outside the stow directory, use the -d and -t flags:

stow -d ~/dotfiles -t ~ bash
  • -d ~/dotfiles — the stow directory
  • -t ~ — the target directory (your home folder)
  • bash — the package to symlink

Advanced commands

# Add a new file to a package later? use Restow (-R)
# It removes old symlinks and creates new ones in one shot:
stow -R bash
 
# Completely remove symlinks for a package with Delete (-D):
stow -D bash
 
# Dry-run (-n / --no) prints what would happen without doing it:
stow -n -v bash
# The -v (verbose) flag is essential here to see what Stow would do.
 
# Stow multiple packages at once:
stow bash vim git
 
# Stow every package in the current directory:
stow *

Dealing with conflicts and ignoring files

Stow never silently overwrites. If a real file already exists where a symlink should go, it throws an error:

# WARNING: in target home:
#   * existing target is not owned by stow: .bashrc

Fix it by removing or backing up the conflicting file first:

mv ~/.bashrc ~/.bashrc.backup
stow bash

Sometimes you want Stow to ignore certain files inside a package — a README.md, .git, or .DS_Store:

stow --ignore="README.md" bash

To avoid typing ignore flags every time, create a .stowrc file inside ~/dotfiles:

echo "--ignore=README.md"  > ~/dotfiles/.stowrc
echo "--ignore=\\.git"     >> ~/dotfiles/.stowrc
echo "--ignore=\\.DS_Store" >> ~/dotfiles/.stowrc

Stow reads .stowrc automatically whenever you run it from the stow directory.

Summary of flags

CommandMeaning
stow bashSymlink everything under bash/ to the target
stow -R bashRestow: rebuild symlinks (clean + create)
stow -D bashDelete: remove all symlinks for the package
stow -n -v bashDry-run with verbose output
stow -d DIR -t TARGET PACKAGESpecify stow dir, target dir, and package

Further reading