User Package Management¶
NixOS allows users to manage packages independently from the base system. Service and normal users can install packages from nixpkgs or other sources in their user profile. This is a powerful mechanism to tailor an application’s runtime environment to the exact needs of the deployment. You can also use this approach to install tools that you want to use interactively.
User packages are installed to ~/.nix-profile
,
consisting of the usual subdirectories like bin, include, lib, etc
Installing packages that are already present in the system environment is safe. This doesn’t use additional space if it’s exactly the same package. Other versions, newer or older than system packages, can be installed without conflicts.
Custom User Environments¶
The user profile can be customized by building an environment with buildEnv
and installing it. Packages from arbitrary sources can be mixed and pinned
to specific versions.
Create a file like myproject_env.nix
which specifies the packages to be installed:
1let
2 # Imports. Which package sources should be used?
3 # Use a pinned platform version
4 # pkgs = import (fetchTarball https://hydra.flyingcircus.io/build/259314/download/1/nixexprs.tar.xz) {};
5 # ...or just use the current version of the platform
6 pkgs = import <nixpkgs> {};
7in
8pkgs.buildEnv {
9 name = "myproject-env";
10 paths = with pkgs; [
11 libjpeg
12 zlib
13 ffmpeg
14 nodejs_18
15 electron
16 ];
17 extraOutputsToInstall = [ "dev" ];
18}
The code shown above defines an environment with 5 packages installed from a specific build of our NixOS 23.05 platform. The pinned version can be newer or older than the installed system version.
Pinning the version of the import prevents unwanted changes in your application’s dependencies but you are responsible for updating the imports to get security fixes.
We recommend to keep the pinned version close to the system version to get the latest security fixes. NixOS re-uses packages if the wanted version is already in the Nix store, saving disk space and reducing installation time.
The URL for the current release can be found in the ChangeLog for the 23.05 platform.
If you want to try NixOS unstable with the newest packages, get the URL from the channel:
1$ curl -w "%{url_effective}\n" -I -L -s -S $URL -o /dev/null https://nixos.org/channels/nixos-unstable/nixexprs.tar.xz
2https://releases.nixos.org/nixos/unstable/nixos-23.11pre489246.4e37b4e55b6/nixexprs.tar.xz
Note that the unstable channel may be broken and that upstream NixOS channels don’t have some additional packages we provide on our platform.
Older NixOS versions than 22.11 usually don’t get security updates anymore.
Links to all staging platform builds for 23.05 can be found here (no production channel, yet):
https://hydra.flyingcircus.io/job/flyingcircus/fc-23.05-staging/release
See https://nixos.org/nixos/packages.html for a list of packages.
Use the attribute name from the list and include it in paths
.
The attribute name can differ from the package name.
For some packages, multiple versions are available.
Dry-run this expression with:
nix-build myproject_env.nix
A result
symlink now points to the generated environment. It can be
inspected and used manually, but is not yet an active part of the user profile.
Run
nix-env -i -f myproject_env.nix
to install the env in your profile. Now its binaries are available in PATH and libraries/include files should get found by the compiler.
To update, install the environment again with the same command.
This picks up changes in myproject_env.nix
and package updates
(if the imports are not pinned to a specific version).
Collisions With Existing Packages¶
Packages included in an environment can collide with packages from other environments or with separately installed packages (we recommend not to do this).
You may encounter an error like this:
1$ nix-env -if myproject_env.nix
2installing 'myproject-env'
3building '/nix/store/c3qwfxvdhjgirvzxdhc2h0wpa59fplvk-user-environment.drv'...
4error: packages '/nix/store/s1vqsx5jd7xxq3ihwxz4sc6h1fwnh3v1-myproject-env/lib/libz.so' and '/nix/store/iiymx8j7nlar3gc23lfkcscvr61fng8s-zlib-1.2.11/lib/libz.so' have the same priority 5; use 'nix-env --set-flag priority NUMBER INSTALLED_PKGNAME' to change the priority of one of the conflicting packages (0 being the highest priority)
5builder for '/nix/store/c3qwfxvdhjgirvzxdhc2h0wpa59fplvk-user-environment.drv' failed with exit code 1
6error: build of '/nix/store/c3qwfxvdhjgirvzxdhc2h0wpa59fplvk-user-environment.drv' failed
You can check for potential collisions by viewing the list of packages in the user profile:
nix-env -q --installed
To avoid/resolve conflicts, remove the package and install the user env afterwards:
1nix-env -e zlib-1.2.11
2nix-env -if myproject_env.nix
Multiple Package Outputs¶
Packages can have multiple “outputs” which means that not all files are
installed by default. If you want to install libraries to build against,
including dev
in extraOutputsToInstall
should be sufficient.
You can check which outputs are available with the following command:
nix show-derivation -f '<nixpkgs>' zlib | jq '.[].env.outputs'
This shows the outputs for zlib
: out
, dev
and static
. -f
sets
the inspected NixOS version, which can be an URL like in myproject_env.nix
.
Assume we have an user env with just zlib
. If extraOutputsToInstall
is empty, these files would be installed:
1$ nix-build myproject_env.nix && tree -l result
2/nix/store/s1vqsx5jd7xxq3ihwxz4sc6h1fwnh3v1-myproject-env
3result
4├── lib -> /nix/store/iiymx8j7nlar3gc23lfkcscvr61fng8s-zlib-1.2.11/lib
5│ ├── libz.so -> libz.so.1.2.11
6│ ├── libz.so.1 -> libz.so.1.2.11
7│ └── libz.so.1.2.11
8└── share -> /nix/store/iiymx8j7nlar3gc23lfkcscvr61fng8s-zlib-1.2.11/share
9 └── man
10 └── man3
11 └── zlib.3.gz
If you add dev
to extraOutputsToInstall
, include
and lib/pkgconfig
would be installed, too:
1$ nix-build myproject_env.nix && tree -l result
2/nix/store/a078dzvn7w7pp3mn0gxig8mpc14p2g4s-myproject-env
3result
4├── include -> /nix/store/ww7601vx7qrcwwfnwzs1cwwx6zcqdjz3-zlib-1.2.11-dev/include
5│ ├── zconf.h
6│ └── zlib.h
7├── lib
8│ ├── libz.so -> /nix/store/iiymx8j7nlar3gc23lfkcscvr61fng8s-zlib-1.2.11/lib/libz.so
9│ ├── libz.so.1 -> /nix/store/iiymx8j7nlar3gc23lfkcscvr61fng8s-zlib-1.2.11/lib/libz.so.1
10│ ├── libz.so.1.2.11 -> /nix/store/iiymx8j7nlar3gc23lfkcscvr61fng8s-zlib-1.2.11/lib/libz.so.1.2.11
11│ └── pkgconfig -> /nix/store/ww7601vx7qrcwwfnwzs1cwwx6zcqdjz3-zlib-1.2.11-dev/lib/pkgconfig
12│ └── zlib.pc
13└── share -> /nix/store/iiymx8j7nlar3gc23lfkcscvr61fng8s-zlib-1.2.11/share
14 └── man
15 └── man3
16 └── zlib.3.gz
Mixing Packages From Different Sources¶
You can import packages from different NixOS versions or other sources:
1let
2 pkgs = import <nixpkgs> {};
3 pkgsUnstable = import (fetchTarball https://releases.nixos.org/nixos/unstable/nixos-23.11pre489246.4e37b4e55b6/nixexprs.tar.xz) {};
4in
5pkgs.buildEnv {
6 name = "myproject-env";
7 paths = with pkgs; [
8 pkgsUnstable.libjpeg
9 zlib
10 ];
11 extraOutputsToInstall = [ "dev" ];
12}
This installs the zlib
from the platform NixOS version but libjpeg
from NixOS unstable (here 23.11pre).