How to handle installation and configuration on a single-user system?

I’m new to Nix and I’m trying to figure out what’s the best way to manage programs and config, since I’m the only user on my machine.

For example with tmux, should I:

  • install and configure tmux system-wide (= the default profile if I understand correctly) with the nixos option
  • install and configure tmux with home manager
  • install tmux system-wide and configure it with home manager

I can’t configure git with a NixOS option, so I have to use Home Manager. If I want to write my gitconfig using Nix, I have to write it under programs.git, which will install git in my profile.

But I also installed git in the default profile. Should I remove it then? What about updates? If git is only installed for my user via Home Manager, will sudo nixos-rebuild switch --upgrade update it? Or does Home Manger manage updates for the programs it installs & configure?

I can also install git system-wide and configure it with Home Manager and home.file

I’m a bit lost. How does your workflow look like? I read a lot of configuration repos on GitHub, but I couldn’t figure out that part. Thanks :slight_smile:


Feel free to. If something depends on git, it’ll get its own.

That depends on whether you have installed it as a system module.

That’s because it’s not set in stone and you’re welcome to do whatever suits you best.


The “default profile” is the root’s profile, i.e. /nix/var/nix/profiles/default to be clear what I mean. That’s a distinct way from using the NixOS options (like systemPackages).

Using NixOS options has the property of always having the package versions in sync with the OS, which is usually considered useful, especially for SW you use often. I think it also simplifies managing the list of packages you want and keeping them up to date, assuming you want to manage the OS config anyway (e.g. via /etc/nixos/.git). I think it’s quite a popular way, though I do not use it personally, as I prefer to decouple the OS from the other packages I use, even on my single-user systems.

I have no idea how this/any approach plays with Home Manager, though; personally I just control some particular dot-files with git, but I’d expect managing configuration usually doesn’t need to be tightly coupled to managing the corresponding binaries (as system services are excluded here).


Is there a way I can use home-manager in my configuration.nix with nixos-rebuild?

Yes, follow the NixOS module installation instructions.

Typically, if you install a package both to the system profile and the user profile then the user one will be used. I.e., the user profile’s bin directory appears before the system one in PATH.


That’s perfect, thank you! :smiley:

I completely avoid user-level things (i.e. nix-env) and handle
everything via /etc/nixos/configuration.nix which I keep in a git repo.
I specify the packages I want installed via systemPackages.

To avoid cluttering my configuration.nix too much my systemPackages
contains a custom package called all, which I define separately using
buildEnv to contain all of the packages I want. This way I can do
things like checkout a particular git revision and enter a nix-shell
with that version of the all package.

In fact I use another layer of indirection: all contains packages
which are interactive and graphical (e.g. abiword, firefox, etc.), as
well as a custom package called basic.

The basic package is another buildEnv, but it contains anything that
might also be useful in scripts (e.g. git, jq, file, psmisc, zip, etc.).
This way, when I’m writing scripts, cron jobs, systemd services, etc. I
can make them depend on basic and use all of the programs I’m used to.

I’ve seen home manager mentioned a few times, but haven’t used it
myself. I’ve been keeping my dotfiles in a git repo for many years. It’s
a bit hacky, but I have an entry in system.activationScripts which
loops through this repo and symlinks all of the entries into my home
directory. This isn’t ideal since it can’t be rolled back and won’t spot
when entries get deleted; but at the moment I’m happy editing my
dotfiles in-place (in a working copy of the repo) rather than doing a
nixos-rebuild to see the changes.

1 Like

I’m using a bit less hacky way – a line in ~/.profile:

alias confgit="git --git-dir='$HOME/.config/conf.git' --work-tree='$HOME'"

so whenever I want to manage my dot-files, I simply use confgit instead of git.

I’m using a bit less hacky way – a line in ~/.profile:

I myself use YADM, which is very similar.


Could you elaborate why is that needed? If you’re deploying these scripts with Nix, cannot you just use ${pkgs.jg}/bin/jq in them and make Nix handle it?

I think it’s about the case when you’re not deploying the scripts with nix. In that case you might prefer #!/usr/bin/env jq which just works on non-Nix-based systems, too.

Alexander Sosedkin via Nix community writes:

Could you elaborate why is that needed? If you’re deploying these
scripts with Nix, cannot you just use ${pkgs.jg}/bin/jq in them and
make Nix handle it?

It’s not “needed”. I just find it tedious to prefix every binary with a
quasiquoted package, once a script gets longer than a few lines.

I much prefer to write substantial scripts in standalone files so I get
editor support, syntax highlighting, linter support, etc. Then my Nix
code will send them through makeWrapper --prefix PATH : "${basic}/bin"
(I have a helper function to reduce this boilerplate) to bake-in all
of my “expected” packages (GNU stuff, Linux stuff, a bunch of
programming language interpreters, compression programs, file conversion
tools, networking tools, etc.). If it turns out that something else is
needed, I’ll either add that to the makeWrapper invocation, or
consider adding it to basic (if it’s generally useful).

I find this less tedious than writing huge strings in Nix, or templating
things for substitute/substituteInPlace/etc. Those approaches also
don’t work for transitive dependencies (e.g. we make sure to write
${}/bin/foo but that tries to invoke bar internally).

Depending on a bunch of stuff that I commonly use also avoids needing to
track down so many (possibly transitive) dependencies: both the
find-out-what-this-script-needs and the find-what-package-provides-this

This is purely a personal preference: if I think a script/derivation
might be useful to others, I’ll usually go to the effort of finding out
its dependencies and passing them to makeWrapper individually.

1 Like