iTranslated by AI
Managing dotfiles with WSL and home-manager: Comparison and usage of 4 methods
Introduction
Nix is a package manager known for its high reproducibility, and home-manager is a tool for managing user environments using Nix.
Recently, I have been building a development environment using Nix.
In the process, I wanted to easily manage tools commonly used across most projects, such as git, with Nix, so I introduced home-manager.
This is just my personal impression...
Although the official manual provides configuration examples for git and other tools, I found it unclear how to write configurations for a package you are encountering for the first time.
Therefore, in this article, I will explain how to use and the differences in behavior of four introduction methods, using git as an example.
home.packagesprograms.<name>home.file.<name>.sourcehome.file.<name>.text
Target Readers
- Already have Nix installed
- Have read
Nix入門andNix入門: ハンズオン編
Verification Environment
- Windows 11
- WSL2
- Ubuntu 22.04.5 LTS
- nix (Determinate Nix 3.8.2) 2.30.1
- home-manager 25.11-pre
Details
> wsl -l -v
NAME STATE VERSION
NixEnv Running 2
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 22.04.5 LTS
Release: 22.04
Codename: jammy
$ nix --version
nix (Determinate Nix 3.8.2) 2.30.1
$ home-manager --version
25.11-pre
$ nix-channel --list
home-manager https://github.com/nix-community/home-manager/archive/master.tar.gz
References
-
Official GitHub
https://github.com/nix-community/home-manager -
Official Manual
https://nix-community.github.io/home-manager/index.xhtml -
Official Manual (Options Reference)
https://nix-community.github.io/home-manager/options.xhtml -
Home Manager - Option Search (search home-manager options)
https://home-manager-options.extranix.com/ -
NixOS Search - Packages (search pkgs)
https://search.nixos.org/packages -
Articles explaining home-manager
https://blog.tomoyukim.net/entry/nix-home-manager/
Preparing home-manager
Installation
Multiple methods are available, but for WSL environments, Standalone installation is the only option.
Execute the following commands one by one:
nix-channel --add https://github.com/nix-community/home-manager/archive/master.tar.gz home-manager
nix-channel --update
nix-shell '<home-manager>' -A install
home.nix and Activating the Environment
After installation, home.nix is generated in the following directory:
~/.config/home-manager/home.nix
In home.nix, you can specify the packages you want to use in your user environment and configure package options.
Then, with the following command, the environment is built and activated based on home.nix:
home-manager switch
Now, let's actually write configurations for git and other tools in home.nix.
From here on, I will explain various configuration methods using git as an example.
Characteristics and Usage of the Main Package Introduction Methods
| Method | Use Case | |
|---|---|---|
| 1 | home.packages |
Just want to install the package |
| 2 | programs.<name> |
Want to install the package and generate configuration files at the same time |
| 3 | home.file.<name>.source |
Want to reuse existing configuration files via symbolic links |
| 4 | home.file.<name>.text |
Want to write the configuration file content directly in home.nix as text |
Personal Impression
For packages that don't need configuration, home.packages is fine; if configuration is needed, programs.<name> or home.file.<name>.source seems good.
Choosing between programs.<name> and home.file.<name>.source is a matter of preference, but I felt that home.file.<name>.source is more reliable.
(programs.<name> lets home-manager generate configuration files nicely; looking at it critically, there is a risk of errors caused by home-manager's processing.)
As for home.file.<name>.text, readability decreases as the number of configuration files increases, so home.file.<name>.source seems easier to manage with appropriate separation.
Check behavior when package is not installed
To make clear what changes when editing home.nix, let's first see the state without the git package installed.
{ config, pkgs, ... }:
{
home.username = "ryu";
home.homeDirectory = "/home/ryu";
home.stateVersion = "25.05";
programs.home-manager.enable = true;
}
Activating the environment, of course, means git installed outside Nix via normal methods is being used.
$ home-manager switch
$ which git
/usr/bin/git
Method 1 home.packages - Package Installation
First, let's look at the most basic method to make git available with Nix.
Write the packages you want to use in home.packages.
{ config, pkgs, ... }:
{
home.username = "ryu";
home.homeDirectory = "/home/ryu";
home.stateVersion = "25.05";
home.packages = [
pkgs.git
];
programs.home-manager.enable = true;
}
Now you can use git managed by Nix.
$ home-manager switch
$ which git
/home/ryu/.nix-profile/bin/git
Let's check which .gitconfig is being referenced.
$ git config --list --show-origin
file:/home/ryu/.gitconfig user.name=MyName
file:/home/ryu/.gitconfig user.email=MyMail
The .gitconfig that was used when git was installed outside Nix is being referenced.
Next, let's manage this .gitconfig with home-manager as well.
Method 2 programs.git - Package Installation & Configuration
If you want to configure settings at the same time as installing the package, use programs.<package name>.
{ config, pkgs, ... }:
{
home.username = "ryu";
home.homeDirectory = "/home/ryu";
home.stateVersion = "25.05";
programs.git = {
enable = true;
userName = "MyNixName";
userEmail = "MyEmail@example.com";
};
programs.home-manager.enable = true;
}
Now, what happened to .gitconfig?
$ git config --list --show-origin
file:/home/ryu/.config/git/config user.email=MyEmail@example.com
file:/home/ryu/.config/git/config user.name=MyNixName
file:/home/ryu/.gitconfig user.name=MyName
file:/home/ryu/.gitconfig user.email=MyMail
/home/ryu/.config/git/config was generated by home.nix.
Meanwhile, /home/ryu/.gitconfig is the original file.
The configuration files are duplicated, so delete the latter.
(Although I'm deleting it here, it's safer to back it up by renaming it.)
$ rm ~/.gitconfig
$ git config --list --show-origin
file:/home/ryu/.config/git/config user.email=MyEmail@example.com
file:/home/ryu/.config/git/config user.name=MyNixName
Behavior When Conflicting with Existing Config Files
If a file already exists where home-manager places the git config, an error like the following occurs:
$ home-manager switch
…
Activating checkLinkTargets
Existing file '/home/jdoe/.config/git/config' is in the way
Please move the above files and try again
From the official manual:
To configure programs and services Home Manager must write various things to your home directory. To prevent overwriting any existing files when switching to a new generation, Home Manager will attempt to detect collisions between existing files and generated files. If any such collision is detected the activation will terminate before changing anything on your computer.
Method 3 home.file source - Symbolic Link for .gitconfig
This method creates a .gitconfig in advance and creates a symbolic link.
{ config, pkgs, ... }:
{
home.username = "ryu";
home.homeDirectory = "/home/ryu";
home.stateVersion = "25.05";
home.packages = [
pkgs.git
];
home.file = {
".gitconfig".source = git/.gitconfig;
};
programs.home-manager.enable = true;
}
In this example, since git is only being installed as a package, home.packages is used.
home.file.<FileName>.source = <FilePath> specifies which file to create a symbolic link to.
home.file = {
".gitconfig".source = git/.gitconfig;
};
Method 4 home.file text - Write .gitconfig Directly in home.nix as Text
This method writes the content of .gitconfig directly in home.nix as text.
{ config, pkgs, ... }:
{
home.username = "ryu";
home.homeDirectory = "/home/ryu";
home.stateVersion = "25.05";
home.packages = [
pkgs.git
];
home.file = {
".gitconfig".text = ''
[user]
name = MyName
email = MyMail
'';
};
programs.home-manager.enable = true;
}
home.file.<FileName>.text = <ConfigText> allows you to directly write the content of <FileName> as text.
home.file = {
".gitconfig".text = ''
[user]
name = MyName
email = MyMail
'';
};
Checking the actual behavior, it confirms that .gitconfig is generated and placed upon environment activation.
$ cat /home/ryu/.gitconfig
cat: /home/ryu/.gitconfig: No such file or directory
$ home-manager switch
$ cat /home/ryu/.gitconfig
[user]
name = MyName
email = MyMail
(Bonus Explanation) How to Find Parameters for programs.git
Where did the userName and userEmail used in Method 2's programs.git come from?
I'll explain three methods to find each parameter.
- A. Search with Home Manager - Option Search
- B. Search the official manual
- C. Read the git.nix file
Basically, A. Home Manager - Option Search is easy to use and recommended.
From the perspective of "how to find primary sources," I'll also introduce B. Search the official manual and C. Read the git.nix file.
A. Search with Home Manager - Option Search
You can search for available options in home-manager at the following site:

B. Search the official manual
Options confirmed in Home Manager - Option Search can also be checked in the official manual.

C. Read the git.nix file
When you check programs.git.enable on Home Manager - Option Search or the official manual, there is a link at the bottom saying Declared by: <home-manager/modules/programs/git.nix>.
For packages like git that have many options and many similarly named options (making it hard to narrow down by search), I personally find it easier to get a comprehensive overview of available parameters by reading the nix file directly.
The parameters defined in options starting from line 101 onwards are the parameters available for programs.git in home.nix.
Sample 1 userName
For example, looking at userName, you can see that the default is null, and a str type is expected.
The description will also be valuable information.
options = {
programs.git = {
...
userName = mkOption {
type = types.nullOr types.str;
default = null;
description = "Default user name to use.";
};
...
Sample 2 extraConfig
Let's also check a more complex parameter.
options = {
programs.git = {
...
extraConfig = mkOption {
type = types.either types.lines gitIniType;
default = { };
example = {
core = {
whitespace = "trailing-space,space-before-tab";
};
url."ssh://git@host".insteadOf = "otherhost";
};
description = ''
Additional configuration to add. The use of string values is
deprecated and will be removed in the future.
'';
};
...
It may seem harder to understand with more information, but what you need to do is quite simple.
Let's compare the writing methods in .gitconfig and nix.home, using the core whitespace example from the example section.
The values set are directly from the example in the
gitdocumentation below.
Comparison
Although detailed definitions are omitted, I think the writing rules are visually understandable.
If you check how to write in .gitconfig in the git documentation, you can infer how to write it in home.nix.
# .gitconfig
[core]
whitespace = trailing-space,space-before-tab,indent-with-non-tab
# home.nix
extraConfig = {
core = {
whitespace = "trailing-space,space-before-tab,indent-with-non-tab";
};
};
For reference, the code used during verification is listed below.
.gitconfig
git config --global core.whitespace trailing-space,space-before-tab,indent-with-non-tab
[core]
whitespace = trailing-space,space-before-tab,indent-with-non-tab
home.nix
programs.git = {
enable = true;
userName = "MyNixName";
userEmail = "MyEmail@example.com";
extraConfig = {
core = {
whitespace = "trailing-space,space-before-tab,indent-with-non-tab";
};
};
};
Verification of configuration application
For verification purposes, I have recreated the .gitconfig that was deleted in the previous session.
$ git config --list --show-origin
file:/home/ryu/.config/git/config core.whitespace=trailing-space,space-before-tab,indent-with-non-tab
file:/home/ryu/.gitconfig core.whitespace=trailing-space,space-before-tab,indent-with-non-tab
(Bonus Explanation) How to Find What Other Packages Can Be Introduced Besides git
You can search for packages available in Nix on this site.
For example, searching for vim gives the following:

You can determine that pkgs.vim is available.
At this point, you know that any method other than Method 2 can introduce it.
- Method 1
home.packages - Method 3
home.file.<name>.source - Method 4
home.file.<name>.text
On the other hand, Method 2 is a technique provided by home-manager, so you need to check home-manager's options.

This time we found it, so we can determine that vim can be managed with Method 2 as well.
- Method 2
programs.<name>
Update History
2025/8/8
I was introduced to a site called Home Manager - Option Search in a comment. It allows you to easily search for options available in home-manager.
- Added
Home Manager - Option Searchto the session(Bonus Explanation) How to Find Parameters for programs.git - Added the relevant site to references
- Adjusted minor wording in each session following the addition
satler
You can search for Home Manager options on a site called Home Manager Option Search! Please check it out!
Discussion
Home Manager Option Search というサイトでHome Managerのオプションを検索することができます!ぜひ確認してみてください!
おお!とても調べやすいです!
教えてくださりありがとうございます