Iteration workflow for configuring home manager

TL;DR What’s your workflow for quickly configuring frequently-tinkered home manager programs without having to rebuild constantly for minor changes?

I know people have different approaches to dealing with their home environment with home manager, ranging from not using it at all, using it separately from NixOS, simply using builtins.readFile or an equivalent to manage it without the Nix language, or deeply integrating it with their NixOS config. I fall into the latter; for reasons like global styling and shared configs across multiple devices (reproducibility), I want to configure almost everything that supports it under home manager because I love its reproducibility, centralization, and modularity.

Of course, having to wait for rebuilds every time I want to test out a config option for Plasma Manager or for Hyprland, for instance, makes the experience frustratingly slow. (I am aware this recent thread is related but have opted to not follow its solutions because of the compromises involved). Moving home manager config away from NixOS is not a solution because that only speeds up rebuilds; it does not reduce the need for frequent rebuilds during iteration.

What workflow do you all use to configure home manager programs? Here are some ideas I’ve thought of:

  • Dealing with it and taking a quick stretch break between every iteration. Tinker with the config, wait a minute to test it out, and tinker again. (slow but simple and reproducible)
  • Writing initial config and then porting it to Nix. For instance, writing out the Hyprland config in its respective hypr/hyprland.conf config file, getting it to a satisfactory working state, and then porting it over. After porting it over, deal with rebuilds (initial config writing is painless, but iteration afterward is slow)
  • Use mkOutOfStoreSymlink to link to a config file on the system, with the downside of being not easily reproducible and managed outside of Nix. (quick but not reproducible). Optionally, get config to a satisfactory state like above using mkOutOfStoreSymlink on a dev branch before porting it to Nix for reproducibility (quick but not reproducible at first, slow but reproducible later)
  • (complicated) For programs with modular configs that allow importing files, write main config with Nix but import a non-reproducible dev file for quick iteration before, eventually, triaging satisfactory changes into Nix with Home Manager periodically. This works great for something like Hyprland, which uses a robust configuration language that allows importing other files and supports live reloading. I implemented this with Hyprland like so:
  wayland.windowManager.hyprland.extraConfig = ''
# DO NOT EDIT THIS FILE! Anything here will be overwritten by home manager.
# Instead, write to the file below:
source=~/.config/hypr/config/hyprland-dev.conf
''
  • (complicated) Copying from the nix store to the config file for an ephemerally writable config that resets to the defined state in the Home Manager config on activation. A demonstration with VSCode is implemented here. This is useful for programs like VSCode which don’t allow importing other files, like with Hypr, and which require frequent iteration. In VSCode’s case, it frequently tries to edit the config file, requiring it to be writable for many features to work properly. (On a side note, I’ve run into an issue with this solution in which home manager can’t back up the ephemeral file, requiring a force flag to overwrite the ephemeral changes.)

I use a mixture of these workflows for different programs at different states of completeness with their configs. My main use case for a quick iteration workflow would be something like Hyprland, which I frequently tinker with and which has fast (live) reloading. I’ve solved the Hyprland situation with the extraConfig source line, but not every program supports importing other files. For instance, VSCode uses a single JSON file to configure, requiring either . All of these options have limitations, though: either too slow or not integrated well with my NixOS configuration. Are there any workflows I haven’t thought of that would be ideal for my situation?

1 Like

Sounds like most of your complaints are about speed. Why is significantly increasing rebuild time not an improvement?

It might be worth investigating what part of your config is triggering such lengthy builds so often. It might be fixable. If relatively few inputs have changed, then the majority of your derivation outputs should be lying around in the nix store already and shouldn’t need to be rebuilt. Typically my config takes something like 20 seconds to “build” (quotes because most of that build is memoized in the nix store)–though it gets longer depending on what I’ve changed.