Skip to content

Home Manager module v2, systemd mounts, options refactoring, tests and more#272

Merged
talyz merged 13 commits intomasterfrom
home-manager-v2
Jan 7, 2026
Merged

Home Manager module v2, systemd mounts, options refactoring, tests and more#272
talyz merged 13 commits intomasterfrom
home-manager-v2

Conversation

@talyz
Copy link
Collaborator

@talyz talyz commented May 25, 2025

This PR is a pretty big refactoring and changes a lot of things. When viewing the diffs, I would recommend hiding whitespace changes.

Replace the current Home Manager module implementation with an interface to the NixOS module

This is the main goal. The other changes, while useful on their own, were mostly done to make this doable.

This should close a whole bunch of issues related to the Home Manager module and massively lessen the maintenance burden of the project, since there's now one unified implementation instead of two disparate ones. This also means that things that were previously not possible, such as using real bind mounts, now are.

The main caveat is that the NixOS module has to be imported into the same configuration as Home Manager for this to work. I can't find any good reason to use the Home Manager module exclusively, but if you have one - do tell.

There are some minor UI and feature differences, mainly on the positive side, but assertions should have been added for any removed or changed functionality.

Fixes #247, fixes #248, fixes #207, fixes #184, fixes #177, fixes #142, fixes #130, fixes #45, fixes #198, fixes #232, fixes #256, fixes #257

Move all submodule options out to a separate file

This makes it possible to import shared submodule options where needed, reducing duplication and complexity.

Use systemd.mounts instead of fileSystems for bind mounts

This removes the need for the home option, as the home directory can be deduced automatically. This was previously not possible due to a long-standing issue in nixpkgs: NixOS/nixpkgs#24570.

It also greatly simplifies the neededForBoot directory creation, since it's either handled automatically by systemd in the initrd or easily done in the postMountCommands.

Fixes #179, fixes #222, fixes #227

Allow setting file linking method

For some files, it's preferable to use symlinks over bind mounts - for example when a program wants to rename the file temporarily. This adds an option (method = "symlink") to keep a file a symlink even when the file exists, which would otherwise trigger the usage of a bind mount.

Closes #146

Add basic NixOS tests

Test the basic and critical functionality of the modules. The tests can be run with nix flake check and are run automatically in the CI checks. Should have been added a long time ago - I've just been lazy :)

cc @Ma27 @eyJhb @nazarewk @MattSturgeon @colemickens @SrEstegosaurio @DaRacci @mjm @collinarnett @zackattackz

@talyz talyz requested review from Mic92 and removed request for Mic92 May 25, 2025 09:36
@talyz talyz mentioned this pull request May 25, 2025
@talyz talyz force-pushed the home-manager-v2 branch 2 times, most recently from f226ec5 to 0e97b02 Compare May 25, 2025 19:27
@DaRacci
Copy link

DaRacci commented May 26, 2025

From what you've described it sounds a lot like what i transformed my impermanence setup to be like a while back (but much more fleshed out); I made change that just redirected all my home declarations for it to the NixOS module to avoid bindfs or symlinks.

Definitely a major improvement with regards to performance.

It may be worth trying to include a notice, or a cleanup for BindFS mounts to prevent any issues during the switch over as I imagine #249 may rear its head out; This change also cause an issue when attempting to live switch a configuration due to in use mounts but that's likely unsolvable.

@talyz talyz force-pushed the home-manager-v2 branch from 0e97b02 to a2f08d2 Compare May 26, 2025 13:55
@eyJhb
Copy link
Contributor

eyJhb commented May 27, 2025

Curious @talyz , I haven't read too much into these changes, but does this fix the current issue with symlink folders not being created? AFAIK there currently is a issue with symlink not creating the folder in the state directory. So you end up with a symlink pointing to a folder that does not exists.

EDIT: Yes it does, you linked this one in the fixes :) #177 thanks! Looks awesome

@cardboardcpu
Copy link

@eyJhb I definitely ran into that so many times I ended up creating my own crappy abstraction to setup the dirs with tmpfilesd so the symlinks are not broken… Would love seeing that fixed. :)

P.D: Thanks for the amazing work here @talyz.

@Shandoo94
Copy link

Shandoo94 commented Jun 2, 2025

I think I have found a bug in the new home-manager implementation.
At a file conflict, the home-manager module can be set to create a backup with a given file extension through backupFileExtenstion, to not fail activation. Currently, the systemd unit for a specified file fails the bind or symlink if the file already exists instead of creating a backup. I think that was not a problem previously.
I tried persisting my zsh _history, but the file gets created as soon as the rebuild command is run, so the bind will always fail.

Source and target directory are also not created with the same permissions, is that intended behavior?

@gigamonster256
Copy link

gigamonster256 commented Jun 3, 2025

I just set this up and it's working great, no complaints about functionality on nixos hosts. However, I use some machines with home-manager standalone and I've written my personal home-manager modules in such a way where it would be really nice to be able to disable the assertions that check if impermanence has been imported correctly (like how home-manager can disable nixpkgs version release check) or only run the assertions if any home.persistence submodule is enabled.

@Ma27
Copy link
Member

Ma27 commented Jun 4, 2025

I think it's worth mentioning that the unit-based approach was pioneered by @WilliButz already with https://github.com/nix-community/preservation.

Perhaps an exchange of experiences could help?

@nixos-discourse
Copy link

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/are-there-better-alternatives-to-the-impermanence-module/64701/8

@different-name
Copy link

Just got this set up on my machine

Replace the current Home Manager module implementation with an interface to the NixOS module

I made a small module to track stray files in persisted directories and files that haven't yet been persisted, and having everything now be in the same format and structure now is very helpful!

assertions should have been added for any removed or changed functionality.

The migration to v2 was very smooth thanks to these assertions

I haven't encountered any problems so far, I use the impermanence module across my entire system

Thank you for all the hard work @talyz ❤️ I have been using impermanence since I first started using NixOS a year ago

Copy link
Member

@MattSturgeon MattSturgeon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not very familiar with the inner workings of impermanence, but I thought I'd give the diff a quick once-over to see if I could help with any small suggestions 🙂

Comment on lines +1 to +9
{ pkgs
, lib
, name
, config
, homeDir
, usersOpts ? false # Are the options used as users.<username> submodule options?
, user # Default user name
, group # Default user group
}:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If going with my suggestion to promote this to a "real" option declaring module, you'd split these args something like:

Suggested change
{ pkgs
, lib
, name
, config
, homeDir
, usersOpts ? false # Are the options used as users.<username> submodule options?
, user # Default user name
, group # Default user group
}:
# Usage: lib.modules.importApply ./submodule-options.nix { /* args */ }
# Applied args
{ pkgs
, outerConfig ? null
, homeDir
, usersOpts ? false # Are the options used as users.<username> submodule options?
, user # Default user name
, group # Default user group
}:
# (Sub)module args
{ lib
, name
, config
}:

The rest of this file is already a valid module and shouldn't need any changes, other than to handle outerConfig as needed.

@Yeshey
Copy link

Yeshey commented Jul 6, 2025

I'm thinking of setting up impermanence (again) should I wait for this to land? Or maybe use this PR directly?

Copy link
Member

@Misterio77 Misterio77 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks amazing, and fixes pretty much everything that was wonky about the HM module before. Thanks so much for the work you put into this, it's so much better than the previous approach.

@different-name
Copy link

I've been using this daily for a bit over a month now, I only have two issues with the new method

  • Applications like Thunar and VSC don't seem to support trashing on system internal mounts, though tools like trashy and trash-cli seem to handle it fine
  • lsblk is quite cluttered with mount points

Other than that, I have no issues!

@mtroberts
Copy link

I'm trying to test this out, working through the assertions. I'm getting the error:

 Failed assertions:
       - The option definition `removePrefixDirectory' in `/nix/store/c0sdj9ibra25kd732rrr5wpffwy6y2pb-source/modules/nixosModules/system/impermanence.nix' no longer has any effect; please remove it.
       ▹ persistence."/cache/hm":
           The use of prefix directories is deprecated and the functionality has been removed.
           If you depend on this functionality, use the `home-manager-v1' branch.

I don't have that option set anywhere in my config. I've never used it.

@mtroberts
Copy link

I'm trying to test this out, working through the assertions. I'm getting the error:

 Failed assertions:
       - The option definition `removePrefixDirectory' in `/nix/store/c0sdj9ibra25kd732rrr5wpffwy6y2pb-source/modules/nixosModules/system/impermanence.nix' no longer has any effect; please remove it.
       ▹ persistence."/cache/hm":
           The use of prefix directories is deprecated and the functionality has been removed.
           If you depend on this functionality, use the `home-manager-v1' branch.

I don't have that option set anywhere in my config. I've never used it.

Never mind, I forgot I was using Geometer1729/persist-retro.

@mtroberts
Copy link

mtroberts commented Aug 5, 2025

Sharing some of my experiences switching to the V2 branch.

Firstly, once I rebuilt I got this error:

Aug 05 10:14:53 nixps systemd[1]: Starting Home Manager environment for mtroberts...
Aug 05 10:14:53 nixps hm-activate-mtroberts[1824]: Starting Home Manager activation
Aug 05 10:14:53 nixps hm-activate-mtroberts[1824]: Could not find suitable profile directory, tried /home/mtroberts/.local/state/nix/profiles and /nix/var/nix/profiles/per-user/mtroberts
Aug 05 10:14:53 nixps systemd[1]: home-manager-mtroberts.service: Main process exited, code=exited, status=1/FAILURE
Aug 05 10:14:53 nixps systemd[1]: home-manager-mtroberts.service: Failed with result 'exit-code'.
Aug 05 10:14:53 nixps systemd[1]: Failed to start Home Manager environment for mtroberts.
Aug 05 10:14:53 nixps systemd[1]: home-manager-mtroberts.service: Consumed 127ms CPU time, 51M memory peak, 59.2M read from disk.

Explicitly persisting the state folders resolved but doesn't happen on V1.

Now I'm getting this error relating to Plasma-Manager:

-- Boot 46f0dbf0068343eba29e129c135124b5 --
Aug 05 10:30:07 nixps systemd[1]: Starting Home Manager environment for mtroberts...
Aug 05 10:30:07 nixps hm-activate-mtroberts[1843]: Starting Home Manager activation
Aug 05 10:30:07 nixps hm-activate-mtroberts[1843]: Activating checkFilesChanged
Aug 05 10:30:07 nixps hm-activate-mtroberts[1843]: Activating checkLinkTargets
Aug 05 10:30:07 nixps hm-activate-mtroberts[1843]: Activating writeBoundary
Aug 05 10:30:07 nixps hm-activate-mtroberts[1843]: Activating configure-plasma
Aug 05 10:30:07 nixps hm-activate-mtroberts[1993]: Traceback (most recent call last):
Aug 05 10:30:07 nixps hm-activate-mtroberts[1993]:   File "/nix/store/wf122xwsbxqdzxjazkfddhir8vdrwf2v-write_config.py", line 343, in <module>
Aug 05 10:30:07 nixps hm-activate-mtroberts[1993]:     main()
Aug 05 10:30:07 nixps hm-activate-mtroberts[1993]:     ~~~~^^
Aug 05 10:30:07 nixps hm-activate-mtroberts[1993]:   File "/nix/store/wf122xwsbxqdzxjazkfddhir8vdrwf2v-write_config.py", line 339, in main
Aug 05 10:30:07 nixps hm-activate-mtroberts[1993]:     write_configs(d, reset_files, immutable_by_default)
Aug 05 10:30:07 nixps hm-activate-mtroberts[1993]:     ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Aug 05 10:30:07 nixps hm-activate-mtroberts[1993]:   File "/nix/store/wf122xwsbxqdzxjazkfddhir8vdrwf2v-write_config.py", line 322, in write_configs
Aug 05 10:30:07 nixps hm-activate-mtroberts[1993]:     config.save()
Aug 05 10:30:07 nixps hm-activate-mtroberts[1993]:     ~~~~~~~~~~~^^
Aug 05 10:30:07 nixps hm-activate-mtroberts[1993]:   File "/nix/store/wf122xwsbxqdzxjazkfddhir8vdrwf2v-write_config.py", line 283, in save
Aug 05 10:30:07 nixps hm-activate-mtroberts[1993]:     with open(self.filepath, "w", encoding="utf-8") as f:
Aug 05 10:30:07 nixps hm-activate-mtroberts[1993]:          ~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Aug 05 10:30:07 nixps hm-activate-mtroberts[1993]: PermissionError: [Errno 13] Permission denied: '/home/mtroberts/.config/klipperrc'
Aug 05 10:30:07 nixps systemd[1]: home-manager-mtroberts.service: Main process exited, code=exited, status=1/FAILURE
Aug 05 10:30:07 nixps systemd[1]: home-manager-mtroberts.service: Failed with result 'exit-code'.
Aug 05 10:30:07 nixps systemd[1]: Failed to start Home Manager environment for mtroberts.
Aug 05 10:30:07 nixps systemd[1]: home-manager-mtroberts.service: Consumed 291ms CPU time, 78M memory peak, 91.3M read from disk.

Not had a chance to get to the bottom of what's causing this yet. Maybe need to use tmpfiles to create the config directory. The only files I explicitly persist for plasma are:

          "/persist/hm" = {
            directories = [
              ".local/share/kwalletd"
            ];
            files = [
              ".config/kwinoutputconfig.json"
            ];
          };
          "/cache/hm" = {
            directories = [
              ".local/share/plasma-manager"
              ".config/xsettingsd"
              ".config/session"
              ".config/gtk-4.0"
              ".config/gtk-3.0"
            ];

@mtroberts
Copy link

mtroberts commented Aug 5, 2025

Now I'm getting this error relating to Plasma-Manager: 

It looks like my intermediate folders (for example .config) are getting created with root permissions. This means anything that tries to create a folder in say, .config or .local doesn't have permission. Any ideas?

@cardboardcpu
Copy link

cardboardcpu commented Aug 11, 2025

I cannot seam to even eval the PR, it fails giving me this error:

❯ : nix flake check github:nix-community/impermanence/home-manager-v2
error: attribute 'home' already defined at /nix/store/pr2nf9bp6fz91vdxii9pv8c4larp1drb-source/flake.nix:190:21
       at /nix/store/pr2nf9bp6fz91vdxii9pv8c4larp1drb-source/flake.nix:182:19:
          181|                 {
          182|                   home-manager.users.bird.home.stateVersion = config.system.stateVersion;
             |                   ^
          183|

What I am doing wrong?

Edit

Aparently Lix is stricter than Nixcpp when it comes to this:

impermanence/flake.nix

Lines 182 to 190 in a2f08d2

home-manager.users.bird.home.stateVersion = config.system.stateVersion;
imports = [
home-manager.nixosModules.home-manager
];
home-manager.users.bird = {
imports = [ ./home-manager.nix ];
home.persistence.main = {
or so I am told.

I can confirm it works fine using Nix.

@marrobHD
Copy link

I switched the repo in the flake.nix
Now it fails with assertions. I don't get why it fails. Home Manager is imported in the flake.

       error:
       Failed assertions:
       - home.persistence: Home Manager used standalone!

         Home Manager has to be imported as a module in your NixOS
         configuration for the persistence module to work properly. See
         https://nix-community.github.io/home-manager/#sec-install-nixos-module
         for instructions.

       - home.persistence: NixOS persistence module missing!

         The Home Manager module requires the NixOS module to work properly. See
         https://github.com/nix-community/impermanence?tab=readme-ov-file#nixos
         for instructions.

This moves the user option out of the options file, keeping only the
submodule options which are also merged and unified to work on both
the system root and user level.
Had to be done in a separate commit for git to track the changes
properly.
If the NixOS persistence module and the Home Manager NixOS module are
imported, automatically add the Home Manager module to all Home
Manager users imports, easing transition and lowering the risk of
incorrect usage.
@talyz
Copy link
Collaborator Author

talyz commented Jan 4, 2026

Just in general, it's icky to have to become root to update what is ostensibly your user-level configuration. This has always been my issue with the idea of the home-manager / NixOS integration.

Yeah, if it was possible to do it without requiring it to be loaded as a NixOS module, that would of course be preferable. However, this was already a requirement in v1 due to activation timing issues, where the users' activation scripts have to run before the users log in.

@talyz
Copy link
Collaborator Author

talyz commented Jan 4, 2026

I switched the repo in the flake.nix Now it fails with assertions. I don't get why it fails. Home Manager is imported in the flake.

More context would be necessary to figure this out. Did you use home-assistant switch or does this happen when you rebuild your NixOS configuration? Could you try the latest version?

@talyz
Copy link
Collaborator Author

talyz commented Jan 4, 2026

I think it's worth mentioning that the unit-based approach was pioneered by @WilliButz already with https://github.com/nix-community/preservation.

Perhaps an exchange of experiences could help?

I don't know enough about preservation or its origins to say for sure, but it sounds likely!

@talyz
Copy link
Collaborator Author

talyz commented Jan 6, 2026

The old user unit approach was nice because the mounts wouldn't start until the user logged in.

If used as intended, it would. The system home-manager-<user>.service unit should start the bind mounts before the user logs in and this has been the only officially supported scenario.

Feel free to work on a way to handle this, though! It definitely sounds like a nice feature to have.

@talyz talyz merged commit f868c97 into master Jan 7, 2026
10 checks passed
@talyz talyz deleted the home-manager-v2 branch January 7, 2026 17:02
@vidhanio vidhanio mentioned this pull request Jan 7, 2026
sebastianrasor added a commit to sebastianrasor/nix-config that referenced this pull request Jan 10, 2026
@philipkbh
Copy link

Now I'm getting this error relating to Plasma-Manager: 

It looks like my intermediate folders (for example .config) are getting created with root permissions. This means anything that tries to create a folder in say, .config or .local doesn't have permission. Any ideas?

Just switched to v2 and I'm running into the same issue. Home-manager can't create the config symlinks in .config because it is owned by root.

@upidapi
Copy link

upidapi commented Jan 10, 2026

That happens if impermanence has to create parent dirs. Since it runs a mkdir -p (as root), then it chowns the specified file/dir to what you set it to. You can solve it by using .tmpfiles to pre create (with the correct perms)/chown the parent directories.

@philipkbh
Copy link

philipkbh commented Jan 11, 2026

Yes, after doing some more troubleshooting, I also figured out the cause. I don't really like the tmpfiles solution, so I went back to using v1 until a proper solution is added. Currently, I don't see any benefit of v2 for me (at least, I'm not aware of any).

@upidapi
Copy link

upidapi commented Jan 11, 2026

It's actually an issue in v1 too, idk why it would differ between v1/v2.

@philipkbh
Copy link

Weird because under v1 I don't run into this issue - there all parent folders belong to my user and not to root.

@somasis
Copy link
Member

somasis commented Jan 12, 2026

Weird because under v1 I don't run into this issue - there all parent folders belong to my user and not to root.

Also having this issue, unfortunately. Having to use tmpfiles to fix it kinda feels like a regression in my opinion...

@upidapi
Copy link

upidapi commented Jan 12, 2026

I think that the reason for the breakage is that (from my understanding) the impermanence now runs as root across the whole system.

I think that having "impermanence" auto chown folders in a users home dir may be a good solution, but I'm weary of possible side effects.

So although a somewhat weird interface, I still think tmpfiles is a good solution, as they are the permission/file management solution across nixos. From my understanding, the reason that it doesn't always break is due to other services themselves using tmpfiles/folders already existing.

@raj-magesh
Copy link

@philipkbh @somasis @upidapi I've created a new issue highlighting this breakage.

IMO creating parent directories with the right ownership (or copying over the ownership from the existing directories in persistent storage) should be automated by impermanence by default and not left to the user to do manually.

This issue didn't happen with V1.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet