Skip to content

Nix

Basic design

Nix installs packages in /nix/store; each package “version” has its own subdirectory, and the name includes a hash over the build inputs. That way multiple versions of the same package can be installed at the same time.

Each package can use specific versions (reference by their name in /nix/store) of other packages (e.g. dynamically linked libraries). This is very similar to docker (“immutable image containing all dependencies”), but makes better use of disk space (and downloads), as many packages can share dependencies, and doesn’t need a mount namespace to run programs (and no volume mappings and so on to access your files).

NixOS

Nix can be used as main OS or just to install additional packages.

nixos-rebuild builds a set of packages with a fixed configuration (into a system “profile”); configuration changes require a rebuild.

Binary Caches

Packages are actually “derivations” - instructions how to create a binary from specific sources. Binary caches provide prebuild binaries of those derivations.

Using a binary cache implies trusting it (the configuration uses GPG keys to sign the binaries).

The default cache is at https://cache.nixos.org/.

Generations and garbage collection

Profiles (both from nix-env and nixos-rebuild) and channels use “generations”; every update will create a new generation, allowing an easy rollback to the previous generation.

Those profiles and so on need to live in well-known places (“gcroots”) so the garbage collector knows what to keep.

nix-collect-garbage seems to be the proper command to cleanup old generations and unreferenced packages.

Multi-User

As packages are immutable and profiles reference explicit package versions, there is no risk (apart from disk space abuse) allowing users to install packages (and updating just means installing new versions) - no other user will be affected by it.

Users allowed to install packages (i.e. use nix-env) must be added to the nix-users group (which protects the nix-daemon socket in /nix/var/nix/daemon-socket/), and nix-daemon must be run.

Note

SUID binaries (and binaries using capabilities) like sudo and ping are not supported in /nix/ for security reasons. In NixOS they are provided through wrappers in /run/wrappers.

nix-channel

Channels are the main source of packages. Updating a channel doesn’t update packages; you need to update the profiles too.

Channels use an alias (that is used to install packages) and point to an URL.

Info

Various tools expect nixpkgs to be available as channel alias; if you don’t want to use nixpkgs-unstable consider adding a different upstream channel as nixpkgs.

Warning

A channel (alias) should be either added as root or as user, not both. You can only update (and list) your own channels, but users can use channels added by root.

add unstable packages channel
nix-channel --add https://nixos.org/channels/nixpkgs-unstable nixpkgs
add nixos-unstable channel as nixpkgs
nix-channel --add https://nixos.org/channels/nixos-unstable nixpkgs
add stable packages channel from nixos release
nix-channel --add https://nixos.org/channels/nixos-23.05 nixos
update channels (as user that added them)
nix-channel --update

nix-env

nix-env can be used to manage “profiles”; each user can have a default profile (~/.nix-profile symlink, defaults to /nix/var/nix/profiles/per-user/${USER}/profile), and you should add ~/.nix-profile/bin to your $PATH to make installed binaries available.

Note

On debian you might want to symlink /usr/share/doc/nix-bin/examples/nix-profile.sh into /etc/profile.d/ to add ~/.nix-profile/bin to $PATH for all users.

  • install packages with nix-env --install --prebuilt-only --attr ${channelalias}.${package}
  • upgrade profile: nix-env --upgrade --prebuilt-only This builds a new “generation” of the profile; you can go back to the previous one with nix-env --rollback.
  • list installed packages with nix-env --query This only lists the “top-level” (installed) packages, not the dependencies.

Warning

[nix-env] uses way too much memory in various cases: https://github.com/NixOS/nixpkgs/issues/38635

  • use https://search.nixos.org/packages to search for packages instead of nix-env --query --available
  • use nix-env --install --attr ${channelalias}.${package} to install packages instead of nix-env --install ${package}

Hint

To avoid compiling packages locally use --prebuilt-only for --install and --upgrade operations.

custom profiles

nix-env supports a --profile option to manage profiles in other locations than ~/.nix-profile.

To make sure the garbage collector sees the profile normal users should put those in /nix/var/nix/profiles/per-user/${USER}/${profile}.

Note

The experimental nix profile seems to put those profiles into ~/.local/state/nix/profiles/ - unclear how the garage collector finds those.

You can then either switch your ~/.nix-profile symlink to a custom profile, or call commands from /nix/var/nix/profiles/per-user/${USER}/${profile}/bin directly (or add it to your $PATH).

Example:

Install and run syncthing as user from nixos channel
nix-env --profile "/nix/var/nix/profiles/per-user/${USER}/syncthing" --install --prebuilt-only --attr nixos.syncthing
systemctl --user enable "/nix/var/nix/profiles/per-user/${USER}/syncthing/lib/systemd/user/syncthing.service"
systemctl --user start syncthing.service
Upgrade (needs nix-channel --update before)
nix-env --profile /nix/var/nix/profiles/per-user/${USER}/syncthing --upgrade --prebuilt-only
systemctl --user daemon-reload
systemctl --user restart syncthing.service

nix-shell -p ...

nix-shell can be used to quickly spawn shells with binaries from specified packages in $PATH.

Test python3.12
$ nix-shell -p python312
[nix-shell:~]$ python --version
Python 3.12.0b2

nix-shell doesn’t maintain anything that would keep installed packages alive when the garbage collector is run.

Note

It seems nix-shell is hardcoded to use the nixpkgs channel.

If you don’t use nixpkgs-unstable (which defaults to a nixpkgs alias) you might either add some nixos-* channel with nixpkgs alias or use somethine like NIX_PATH=nixpkgs=/nix/var/nix/profiles/per-user/root/channels/nixos nix-shell ... to temporarily alias it to some other channel.

Flakes

Flakes are an alternative to channels. They are built such that one flake can depend on others.

Note

Flakes are experimental and need to be enabled like this:

~/.config/nix/nix.conf or /etc/nix/nix.conf
experimental-features = nix-command flakes

A flake is a nix expression of an attribute set in flake.nix in a directory (usually from a git repository), with a specific set of attributes.

A flake can list various inputs (using https://github.com/NixOS/flake-registry to find them by default); those are directories containing flakes again or any other nix expression in default.nix.

Flakes are designed to be “pure”; they currently don’t know the platform they are used on, and must contain definitions for all platforms they support. See flake-utils to help with this.