Guix Home is not a good place for dotfiles*
I switched to Guix System ~3 years ago on my desktop. I use it for development/entertainment and even gaming (thanks to Flatpak).
Like most Guix/Nix users, I have that urge to manage EVERYTHING in Guix. Nix’s home-manager was getting popular around that time, and Guix Home quickly followed. Needless to say, I was on board!
Since I only have limited experience with home-manager, this post only focuses on Guix Home.
What counts as dotfiles?
I have checked out some dotfile repos out there. I think everyone has their own opinions on this, for example, one would consider the whole Guix System config as dotfiles, but here in my title, I’d only count the configuration files for my commonly used tools, such as Emacs, fish (Bash), terminal emulators like alacritty/ghostty, tmux, window managers sway/niri, and so on. And nowadays, agent tools (I’ve been using pi-coding-agent recently).
Methods to manage dotfiles with Guix Home
Guix Home also provides a wide variety of options for managing dotfiles, for example:
home-files-service-typehome-dotfiles-service-typehome-xdg-configuration-files-service-type
There are also application-specific services, like
home-openssh-service-typehome-bash-service-typehome-fish-service-typehome-mpv-service-type
… and a lot more
The Problem
They’re all great tools, especially home-dotfiles-service-type; I’m able to dump my existing dotfiles right into Guix Home, but they all share the same problem that hurts the whole flow: it symlinks the config file to the immutable Guix store.
That’s not wrong; that’s the whole point of Guix/Nix: it manages everything in the store, and you can use it to control the “generations”, roll-back and switch at any point. That’s an absolutely killer feature, and it works so well with
- system config - reboot into disaster? Just select a previous working generation!
- package management - never forget about which package to install.
- background daemons - which systemd unit file did I just change?
But not for the dotfiles that you want to change often, I tweak my Emacs config every now and then, sometimes I want to try different keybindings in niri, and many times I want to write a new extension for pi, and I still want them to be git-tracked. With the Guix Home managed services, I need to
- go to my Guix configuration repo
- make the change
guix home reconfigure- try it out
- it works, good, commit the change.
- it doesn’t work, well, tweak it again and go back to step 2
Oh did I mention reconfigure takes forever? Guix often likes to contact substitute servers when I make no change to my packages (this might be a solvable problem but I didn’t bother). Imagine wanting to add/change a niri keybinding (which has config hot reload by default): instead of verifying it in 1s, you now need a 1min loop. And good luck if you happen to have just done a guix pull but forgotten to reconfigure, only to find out you have to wait for LibreWolf to compile because it’s not available in the substitute server yet…
Stow
And yes, all of that has happened to me, and I fail to think of a good reason to keep doing this. The benefit of being able to roll back can come from a git-tracked .dotfiles repo too, symlinked into place with stow. So the other day I just spun up a coding agent, asked it to migrate those back to a standalone dotfiles repo, and baam, just 5 mins later, I can edit my dotfiles freely again, and every change is still tracked.
Closing
Guix (and Nix) are great pieces of software that changed the way I manage my servers and desktop, but the “all in one” mindset actually constrained me for a long time, just like someone trying to apply a “design pattern” or “tech stack” to every project – a wise man once said: it’s always about trade-offs.
I still use a lot of Guix Home services, to manage those configurations I rarely change, like gpg-agent, GTK themes etc, but I finally achieved freedom of dotfiles after breaking out of the “all in one” mindset (pardon the exaggeration).