How to manage dotfiles with home-manager?

I already have a setup with home-manager. The thing I want to know is if there is an easy way rather than doing home-manager switch every time I do a change.

For example, I have my nvim config in ~/dotfiles/config/nvim and my home-manager/home.nix has this setup:

home.file = {
  ".config/nvim" = {
    source = ../config/nvim;
    recursive = true;
  };
}

This is not only for nvim, but for other configs like wezterm, a terminal that reloads the config on save.

Is there a way I could do that with home-manager? Is very tedious to change something and the need of creating a new generation just to see the new change.

Thank you!

4 Likes
home.file = {
  ".config/nvim" = {
    source = config.lib.file.mkOutOfStoreSymlink ../config/nvim;
  };
}

btw if you are using flakes you need to use abslute path as string like:

home.file = {
  ".config/nvim" = {
    source = config.lib.file.mkOutOfStoreSymlink "/home/algus/dotfiles/config/nvim"
  };

if you pass a path instead of string on flakes like in:

home.file = {
  ".config/nvim" = {
    source = config.lib.file.mkOutOfStoreSymlink ../config/nvim;
  };
}

it will copy your config to store before creating a symlink and you will need to home-manager switch --flake everytime (note: --impure might bypass copying i didint tried tough)

note: you can use functions to abstract some of abslute paths

7 Likes

Amazing. Thanks for the help :smiley:
This makes it a lot easier for these kind of configurations

1 Like

This is one of the more helpful threads I found by searching for this issue, so I wanted to add something that might be useful. I’m very new to all this, so I’m sorry if it’s obvious!

if you are using flakes you need to use abslute path as string

According to this comment, you can re-use home-manager’s config variable instead of hardcoding the home path. In other words, use ${config.home.homeDirectory} instead of /home/user. Since home-manager requires that be set anyway, and these symlinks are probably going to be created inside the home directory, it seems like a clear way around the “must use absolute paths” issue, as well, without needing other functions.

7 Likes

Hi,

I just wanted to know, where can I find the documentation to know more about this contrib.lib.file.mkOutOfStoreSymlink option ?

Well, since is a very simple function, no documentation is really needed.

Here is all it does:

3 Likes

Thank you for adding the link. Though it feels critical to mention that there is ALWAYS a need for documentation. Without documentation, the only ways to know this function even exists is to either have read through the code base yourself or be directly told by someone else. There is no mention of this thing anywhere in the home-manager manual (even in the release notes for when it was added).

Again thanks for taking the time to link the specific commit it was added in as well. It does include some useful info in the commit message.

11 Likes

An update on a flakes case

If you are using flakes, you have 3 options:

  1. Use absolute path like "/home/algus/my_nixos_conf/dotfiles/foo"
  2. Use config.home.homeDirectory like
    "${config.home.homeDirectory}/my_nixos_conf/dotfiles/foo"
  3. Use inputs.self like "${inputs.self}/dotfiles/foo"

Example that shows how to pass input.self from flake.nix to home.nix through some module in between:

# flake tree
~/nixos_config/                                                                                                                                                            
├── configs                                                                                                                                                              
│   ├── 1.cfg                                                                                                                                                             
│   ├── 2.cfg                                                                                                                                                           
│   └── 3.cfg                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    
├── flake.lock                                                                                                                                                           
├── flake.nix                                                                                                                                                            
└── hosts                                                                                                                                                                         
    └── user
        └──configuration.nix                                                                                                                                                           
        └──home.nix
# ~/nixos_config/flake.nix
{
  description = "A minimal flake wrapper for system configuration";

  inputs = {
    # Tracks the stable NixOS release channel
    nixpkgs.url = "github:nixos/nixpkgs/nixos-26.05";
    home-manager = {
        # for stable releases versions should match
        url = "github:nix-community/home-manager/release-26.05";
        # dependency for decrease download size
        inputs.nixpkgs.follows = "nixpkgs";
    };
  };

  outputs = { nixpkgs, ... } @ inputs:
  {
    # user is a hostname
    nixosConfigurations.user = nixpkgs.lib.nixosSystem {
        # extra arg for every module
        specialArgs = { inherit inputs;};
        modules = [
          ./hosts/user/configuration.nix
        ];
    };
  };
}
# part of ~/nixos_config/hosts/user/configuration.nix
{ config, pkgs, inputs, ... }:
{
  home-manager = {
    # same as specialArgs but for the home-manager
    extraSpecialArgs = {inherit inputs;};
    users = {
        "user" = import ./home.nix;
    };
  };
}
# ~/nixos_config/hosts/user/home.nix
{ config, pkgs, lib, inputs, ... }:
let
  SymLink = config.lib.file.mkOutOfStoreSymlink;
  # Option 1
  cfg_path_1 = "/home/user/nixos_config/configs";

  # Option 2
  cfg_path_2 = "${config.home.homeDirectory}/nixos_config/configs";

  # Option 3
  #   inputs.self is from the root flake.nix
  #   According to https://nix.dev/manual/nix/2.28/command-ref/new-cli/nix3-flake#flake-inputs
  #   > The special input named self refers to the outputs and source tree of *this* flake.
  cfg_path_3 = "${inputs.self}/configs";

  ### cfg_path_1, cfg_path_2 are equal
  ###  You will be able to edit files (both .cfg and example_) and see result immediately
  ###  
  ### cfg_path_3 is different
  ###  you will need to rebuild the flake to see result after editing 3.cfg (example_3 is read only)
in
{
  home.username = "user";
  home.homeDirectory = "/home/user";

  home.file = {
    ".config/example_1".source = SymLink "${cfg_path_1}/1.cfg";

    ".config/example_2".source = SymLink "${cfg_path_2}/2.cfg";

    # in this case the SymLink is redundant, it will not work as above
    #".config/example_3".source = SymLink "${cfg_path_3}/3.cfg";
    ".config/example_3".source = "${cfg_path_3}/3.cfg";
  };

}
1 Like