Making Dotfiles Visible: A Deep Dive into GNU Stow's --dotfiles Flag
The Hidden File Problem
If you've ever managed dotfiles with GNU Stow, you've likely encountered the
visibility problem: your repository is littered with hidden files and
directories that require ls -la
to see. This makes browsing the repository in
IDEs, GitHub, or terminal file managers frustrating and opaque.
I recently solved this problem by restructuring my entire
dotfiles repository using GNU Stow's
--dotfiles
flag in
commit d1ddce5. The result?
Every configuration file is now immediately visible while maintaining proper XDG
Base Directory compliance when deployed.
Understanding GNU Stow's --dotfiles Flag
GNU Stow's --dotfiles
flag, introduced in version 2.3.0, enables special
preprocessing for files and directories with a dot-
prefix. When this flag is
used, Stow transforms the prefix during symlink creation:
# Repository structure (visible)
fish/dot-config/fish/config.fish
fish/dot-bashrc
# After stowing with --dotfiles
~/.config/fish/config.fish -> fish/dot-config/fish/config.fish
~/.bashrc -> fish/dot-bashrc
The transformation rules are simple but powerful:
dot-
prefix becomes.
(period)dot-config
becomes.config
dot-vimrc
becomes.vimrc
- Nested structures are preserved:
dot-config/nvim/init.lua
→.config/nvim/init.lua
The Transformation: Before and After
Before: Hidden File Chaos
dotfiles/
├── .vimrc
├── .tmux.conf
├── .gitconfig
├── .config/
│ ├── nvim/
│ ├── fish/
│ └── starship.toml
└── .scripts/
Browsing this requires hidden file visibility, and IDEs often struggle with indexing.
After: Complete Visibility
dotfiles/
├── dot-vimrc
├── dot-tmux.conf
├── dot-gitconfig
├── dot-config/
│ ├── nvim/
│ ├── fish/
│ └── starship.toml
├── dot-scripts/
└── brew/
└── Brewfile
Every file is immediately visible with standard ls
, IDEs can index everything,
and the structure is self-documenting.
Implementation Details
The restructuring involved 118 files across multiple categories:
1. XDG Config Directory Migration
All .config/
directories were transformed to dot-config/
:
# Applications affected (50+ configs)
.config/nvim/ → dot-config/nvim/
.config/fish/ → dot-config/fish/
.config/starship/ → dot-config/starship/
.config/lazygit/ → dot-config/lazygit/
# ... and many more
2. Root Dotfiles Transformation
Traditional dotfiles got the dot-
prefix:
.vimrc → dot-vimrc
.tmux.conf → dot-tmux.conf
.gitconfig → dot-gitconfig
.bash_aliases → dot-bash_aliases
3. Bootstrap Script Overhaul
The deployment script was completely rewritten to handle the new pattern:
#!/usr/bin/env bash
# Stow packages using --dotfiles flag
for package in bash editorconfig env fish nvim tmux vim snippets \
starship lazygit lazyvim wezterm nushell yazi raycast \
zellij marimo bat aerospace sesh ripgrep ghostty; do
stow --target=$HOME --dotfiles $package
done
# Stow packages without --dotfiles (special cases)
for package in git scripts; do
stow --target=$HOME $package
done
# Install Homebrew dependencies
brew bundle install --file=brew/Brewfile
The Technical Deep Dive
How --dotfiles Works Internally
According to the
GNU Stow manual,
the --dotfiles
flag adds a preprocessing step that:
- Scans package directories for files/folders with
dot-
prefix - During symlink creation, replaces
dot-
with.
in the target path - Preserves the original filename in the package directory
- Handles nested structures correctly
Edge Cases and Considerations
The transformation has some nuances:
- Files without
dot-
prefix are processed normally dot-
prefixed files are never ignored by default ignore patterns- The flag must be used consistently across all stow operations
Package Management Flexibility
One major benefit is granular package management:
# Install specific configurations
stow --dotfiles --target=$HOME fish
stow --dotfiles --target=$HOME nvim
# Remove specific configurations
stow --delete --dotfiles --target=$HOME fish
# Reinstall with updates
stow --restow --dotfiles --target=$HOME nvim
Real-World Benefits
Developer Experience Improvements
- IDE Integration: All files are indexed and searchable
- GitHub Browsing: Repository structure is immediately clear
- Code Reviews: Changes to configuration files are obvious
- Documentation: Self-documenting directory structure
Maintenance Advantages
- Debugging: Easy to locate specific configuration files
- Backup Verification: Visual confirmation of what's being tracked
- Selective Syncing: Clear package boundaries for partial deployments
- Team Sharing: Colleagues can understand structure at a glance
Migration Strategy
If you're considering this transformation:
1. Backup Everything
git checkout -b dotfiles-backup
git push origin dotfiles-backup
2. Transform Incrementally
# Start with one package
git mv .config/fish dot-config/fish
stow --delete fish # unstow old version
stow --dotfiles fish # stow new version
3. Update Bootstrap Scripts
Modify your deployment scripts to use --dotfiles
flag consistently.
4. Test Thoroughly
Verify all configurations work as expected before committing fully.
Gotchas and Limitations
Mixed Package Handling
Some packages might need special treatment. In my setup, I handle git
and
scripts
packages differently:
# These use --dotfiles
stow --dotfiles fish nvim tmux
# These don't (they manage their own dot-prefixing)
stow git scripts
File History Preservation
Use git mv
for renames to preserve file history:
git mv .vimrc dot-vimrc
git mv .config/fish dot-config/fish
Tool Integration
Some tools might be confused by the new naming. Document any special cases in your README.
Conclusion
GNU Stow's --dotfiles
flag solves a fundamental usability problem with
dotfiles management. By making configuration files visible in repositories while
maintaining proper deployment locations, it dramatically improves the developer
experience.
The transformation requires careful planning and testing, but the benefits—immediate visibility, better IDE support, clearer repository structure—make it worthwhile for any serious dotfiles setup.
If you manage dotfiles with Stow, consider implementing this pattern. Your future self (and anyone browsing your configurations) will thank you.
Resources
- My dotfiles repository with full --dotfiles implementation
- GNU Stow Manual: Dotfiles
- Commit d1ddce5 showing the complete transformation