Strategies for declarative approaches to programs with mutable configuration files

I’m setting up a system with NixOS + Homemanager, which is mostly going quite smoothly. One difficulty I am having is with a few applications that use “mutable” configuration files. I’m not sure if that’s a meaningful terminology, but one example would be the file manager Thunar, which saves its settings in an .xml file. The .xml file also tracks more dynamic things, such as the last view used, or the column widths, so it changes frequently to reflect any changes one makes via the GUI. This seems to me (unless I’m missing something) to create a challenge for using Home manager.

I brainstormed this with an LLM and it gave me three options, neither of which seem very attractive.

1. Don’t use HM to manage Thunar

In some ways this makes sense. If the .xml file is changing dynamically, then I shouldn’t want to be declaring it. On the other hand, there are a few settings in the .xml that seem to change often, but there are also several that I never want to change. I would like to declare these in a completely automated and reproducible way.

2. Use home.file with force = true

This takes the opposite extreme, where now none of the dynamically-changed settings in the .xml would persist. This seems even less attractive than 1.

3: Manage Defaults with xfconf.settings Module (If Available)

I’ll paste what the LLM said:

If you want Nix to control the defaults, but allow GUI edits to persist, some Home Manager modules offer this.
For Thunar/xfce4, unfortunately, there isn’t official xfconf.settings support in Home Manager yet, but some people:
:white_check_mark: Provide dconf.settings or xfconf.settings equivalents for other apps
:white_check_mark: Or use wrapper scripts to load default configs at session start
If you’re interested, you can approximate this by:

  • Keeping a default thunar.xml somewhere
  • Using a systemd ExecStartPre script or similar to copy it only if the file doesn’t exist
  • After first login, the file stays mutable

This one seems like a reasonable compromise to me, but it also seems a bit hackish, so I’m wondering if the LLM is steering me down the wrong rabbit hole.


Are there other approaches? How do you handle this type of situation? I have singled out Thunar, but there are actually a handful of GUI-based apps that I use for which this general issue comes up in various ways.

There’s a secretly deranged 4th option: patch the upstream code (yes I’ve done this in some cases).

5th option would be to implement merging the declarative + mutable config yourself, I’ve never tried this myself as I’ve no idea how to go about it.

Generally the approaches I’ve seen are to go full declarative or full imperative as options 3 and 5 could be quite flaky. Ideally there’d be some some of “include” semantics that allows you to split the app config across multiple files, but yeah, ultimately I’d go with option 1 if option 4 is unrealistic.

1 Like

Another option is to wrap your program to run an idempotent normalization process on the file before starting. The discord package in nixpkgs actually uses this approach to disable prompting the user to update it.

It’s definitely a more complex idea than some, though.

5th hidden approach: use a program to mutate the configuration file and call it during home manager#'s activation. This is the approach used by plasma-manager

1 Like

Thanks everyone for these suggestions. They are a bit more involved than I was hoping would be possible! I was wondering what you think of something like the following, which seems simpler to me, but is certainly less sophisticated:

  1. Periodically make a copy of a dynamically-modified configuration file like thunar.xml in some central location that is version-controlled. In particular, update the copy before rebuilding.
  2. During home manager activation, replace the existing thunar.xml with the copy in the central location.

What types of problems do you see potentially arising from this strategy?