Using GNU Stow for Dotfiles in a DevContainer
GNU Stow turns a dotfiles directory into a tidy symlink farm, and its idempotence makes it a natural fit for a devcontainer's re-running bootstrap. This page uses Stow to link dotfiles into $HOME, so re-runs converge and there's nothing to duplicate.
Prerequisites
You need a Stow-structured dotfiles repo and Stow in the container.
- A dotfiles repo laid out as Stow packages.
stowinstalled in the image.- The
dotfileskeys pointing at your repo.
Step-by-Step Implementation
- Lay out dotfiles as Stow packages.
dotfiles/zsh/.zshrc
dotfiles/git/.gitconfig
- Install Stow and apply in the bootstrap.
#!/usr/bin/env bash
set -e
command -v stow >/dev/null || sudo apt-get install -y stow
cd "$HOME/.dotfiles" && stow zsh git
- Point the dotfiles keys at the repo.
{ "dotfiles": { "repository": "https://github.com/you/dotfiles", "installCommand": "install.sh" }, "remoteUser": "vscode" }
- Verify the symlinks exist.
readlink ~/.zshrc # -> .dotfiles/zsh/.zshrc
Common Pitfalls
Stow issues are conflicts with existing files or a wrong layout.
| Symptom | Root Cause | Remediation |
|---|---|---|
| stow: conflict on existing file | A real file blocks the symlink | Remove/adopt it, then re-stow |
| Nothing gets linked | Wrong package directory layout | Structure as package/relative-path |
| Re-run duplicates nothing but errors | Already-linked treated as conflict | Use --restow to refresh |
| stow not found | Not installed in the image | Install stow in the bootstrap or image |
Conclusion
GNU Stow makes dotfiles a reversible symlink farm: each package directory maps into $HOME, and re-applying is idempotent, so a devcontainer's re-running bootstrap converges cleanly. Structure your repo as Stow packages and the bootstrap stays trivially correct.
FAQ
Why use Stow over a hand-written symlink script?
Stow is idempotent and reversible by design: re-applying converges, and stow -D cleanly removes links. A devcontainer re-runs the bootstrap on every create, so Stow's convergence means no duplicated links or accumulated state, without hand-guarding every ln.
How should I lay out a Stow dotfiles repo?
One package directory per tool, mirroring the path relative to $HOME. For example zsh/.zshrc and git/.gitconfig; running stow zsh git links ~/.zshrc and ~/.gitconfig. The structure makes what-links-where obvious.
What if a real file already exists where Stow wants a link?
Stow reports a conflict rather than clobbering it. Remove or adopt the existing file (Stow's --adopt can absorb it into the package), then re-stow. This safety is why Stow is predictable in a shared bootstrap.
Related
- Up to Automating Dotfiles Sync Across Containers — the dotfiles overview.
- Bootstrapping Dotfiles with chezmoi in a DevContainer — a templating alternative.
- Shell Environment Customization: zsh, fish, bash — the shell Stow configures.