$linuxjunkies
>

How to Manage Dotfiles with GNU Stow

Use GNU Stow to turn a Git repository into a symlink farm for your dotfiles — deploy any config to a new Linux machine in under a minute.

IntermediateUbuntuDebianFedoraArch8 min readUpdated June 7, 2026

Before you start

  • Git installed and a basic understanding of git add/commit/push
  • A remote Git host account (GitHub, GitLab, Codeberg, or self-hosted)
  • Familiarity with navigating the terminal and editing files in $HOME
  • GNU Stow 2.3 or later (check with stow --version)

Dotfiles are the personality of your Linux setup — your shell aliases, editor config, terminal colors, and window manager rules all live in hidden files scattered across $HOME. The problem is tracking them. Copy them manually and they drift out of sync. Symlink them by hand and you forget which links point where. GNU Stow solves this cleanly: it turns a plain directory tree into a symlink farm, letting you keep every config file in a single Git repository and deploy it to any machine in seconds.

What GNU Stow Does

Stow is a symlink manager, nothing more. You put your dotfiles inside a stow package directory, run stow, and it creates symlinks in a target directory (by default, the parent of the package directory) that mirror the package's layout. It does no copying, no templating, no encryption — just symlinks. That simplicity is its strength.

The mental model: your repo lives at ~/.dotfiles/. Inside it, each subdirectory is a package — bash, nvim, tmux, etc. The files inside those packages are laid out exactly as they should appear relative to $HOME. Stow creates the symlinks; Git tracks the real files.

Install GNU Stow

Stow is in every major distribution's repositories.

Debian / Ubuntu:

sudo apt install stow

Fedora / RHEL / Rocky Linux:

sudo dnf install stow

Arch Linux:

sudo pacman -S stow

Create the Dotfiles Repository

Step 1: Initialize the directory and Git repo

Pick a location. ~/.dotfiles is conventional and keeps it hidden from casual ls output.

mkdir -p ~/.dotfiles
cd ~/.dotfiles
git init

Step 2: Understand the directory layout

Each immediate subdirectory of ~/.dotfiles is a Stow package. Inside each package, recreate the path from $HOME to the config file. For example, if you want to manage ~/.bashrc and ~/.config/nvim/init.lua, the layout looks like this:

~/.dotfiles/
├── bash/
│   └── .bashrc
└── nvim/
    └── .config/
        └── nvim/
            └── init.lua

When you stow the bash package from inside ~/.dotfiles, Stow creates ~/.bashrc → ~/.dotfiles/bash/.bashrc. When you stow nvim, it creates ~/.config/nvim/init.lua → ~/.dotfiles/nvim/.config/nvim/init.lua.

Migrate Existing Dotfiles into the Repo

Step 3: Move files and create package directories

The key rule: move the real file into the repo, then let Stow put the symlink back. Never copy — the file in the repo must be the canonical version.

# Create the bash package and move .bashrc into it
mkdir -p ~/.dotfiles/bash
mv ~/.bashrc ~/.dotfiles/bash/.bashrc

# Create the nvim package preserving the subdirectory path
mkdir -p ~/.dotfiles/nvim/.config/nvim
mv ~/.config/nvim/init.lua ~/.dotfiles/nvim/.config/nvim/init.lua

If the original file doesn't exist yet (fresh machine), just create the directory structure and add the file directly inside the repo.

Step 4: Stow the packages

Always run stow from inside ~/.dotfiles, targeting $HOME explicitly with -t to avoid surprises.

cd ~/.dotfiles
stow -t ~ bash
stow -t ~ nvim

To stow everything at once, pass all package names or use a loop:

cd ~/.dotfiles
for pkg in */; do stow -t ~ "${pkg%/}"; done
ls -la ~ | grep dotfiles
ls -la ~/.config/nvim/

You should see output similar to (exact paths will vary):

.bashrc -> .dotfiles/bash/.bashrc
init.lua -> /home/user/.dotfiles/nvim/.config/nvim/init.lua

Commit and Push to Git

Step 6: Add a .gitignore and commit

Exclude anything sensitive or machine-local you don't want committed.

cat > ~/.dotfiles/.gitignore <<'EOF'
.DS_Store
*.swp
*.secret
EOF

git -C ~/.dotfiles add -A
git -C ~/.dotfiles commit -m "Initial dotfiles"
# Add your remote and push
git -C ~/.dotfiles remote add origin [email protected]:yourname/dotfiles.git
git -C ~/.dotfiles push -u origin main

Bootstrap a New Machine

Step 7: Clone and stow on a fresh system

On a new machine, install Stow, clone your repo, then stow each package. Because the target files don't exist yet, Stow creates fresh symlinks with no conflicts.

git clone [email protected]:yourname/dotfiles.git ~/.dotfiles
cd ~/.dotfiles
for pkg in */; do stow -t ~ "${pkg%/}"; done

If a config file already exists on the new machine (e.g., a default .bashrc placed by the distro), Stow will refuse to overwrite it and print a warning. Back up and remove the conflicting file first, then re-run stow.

Day-to-Day Workflow

Adding a new config file is three steps: create the package directory structure, move the file in, stow it.

# Example: add tmux config
mkdir -p ~/.dotfiles/tmux
mv ~/.tmux.conf ~/.dotfiles/tmux/.tmux.conf
stow -t ~ tmux
git -C ~/.dotfiles add tmux/.tmux.conf
git -C ~/.dotfiles commit -m "Add tmux config"

To remove a package's symlinks without deleting the files in the repo, use -D:

stow -t ~ -D tmux

To restow (remove then re-create symlinks, useful after restructuring), use -R:

stow -t ~ -R nvim

Handling Machine-Specific Configs

Some files differ between machines — your work laptop might need a different Git user email than your home desktop. Two clean approaches:

  • Local override files: Keep a base ~/.gitconfig in the repo and use Git's includeIf directive to pull in a machine-local file that Stow doesn't manage (and that you add to .gitignore).
  • Per-machine packages: Create packages named work-bash or home-nvim and only stow them on the relevant machine. A short bootstrap script can handle this automatically based on hostname.
# Bootstrap snippet: stow common packages plus machine-specific ones
HOST=$(hostname -s)
COMMON_PKGS=(bash nvim tmux git)

for pkg in "${COMMON_PKGS[@]}"; do
  stow -t ~ "$pkg"
done

[[ -d "$HOST" ]] && stow -t ~ "$HOST"

Troubleshooting

Stow reports a conflict

If Stow says a file already exists and is not a symlink to the repo, the real file is in the way. Back it up and remove it:

mv ~/.bashrc ~/.bashrc.bak
stow -t ~ bash

Always run Stow from inside the dotfiles directory or use -d ~/.dotfiles -t ~ explicitly. Running it from the wrong directory produces broken relative symlinks.

stow -d ~/.dotfiles -t ~ bash

Stow folding causes unexpected behavior

Stow uses "tree folding": if an entire directory can be represented by a single symlink, it will symlink the directory rather than individual files inside it. This can surprise you when another tool writes a new file inside what it thinks is a real directory but is actually a symlink. Use --no-folding to force per-file symlinks:

stow -t ~ --no-folding nvim
tested on:Ubuntu 24.04Fedora 40Arch rollingDebian 12

Frequently asked questions

What happens if a dotfile already exists on the target machine when I run stow?
Stow refuses to create a symlink if a real file already exists at that path and prints a conflict warning. Back up and remove the existing file, then re-run stow.
Can I use Stow with XDG config files inside ~/.config?
Yes. Recreate the subdirectory path inside your package — for example, nvim/.config/nvim/init.lua — and Stow will create ~/.config/nvim/init.lua as a symlink. You may need to create the ~/.config directory first if it doesn't exist.
Is it safe to store dotfiles on a public GitHub repository?
Only if you audit them carefully. Never commit API keys, SSH private keys, or passwords. Use a .gitignore to exclude sensitive files, and consider a private repo or tools like git-crypt for anything that must be encrypted.
What is Stow's tree-folding behavior and when should I disable it?
Stow may symlink an entire directory instead of individual files inside it when the whole directory belongs to one package. This breaks if another program writes new files into that directory expecting it to be real. Use --no-folding to force Stow to create individual file symlinks instead.
Do I need to re-run stow after editing a managed config file?
No. Because the target is a symlink, any edits you make via the symlink path go directly into the file inside your repo. Just git add and git commit when you are ready to save the change.

Related guides