Nix is a functional package manager for Linux and other Unix systems, making the management of packages more reliable and easy to reproduce.
With a traditional package manager, when updating a package, a new version is downloaded and used to overwrite its associated files. Changes can’t be undone. If for a reason, one or more files are not correctly updated during the upgrade, those files of the package are going to be corrupted. This could make the entire package not functional. In addition, if different packages require different versions of the same package as a dependency, at least one is going to be broken.
This article presents what Nix package manager is, the various deployment options and how to start with it. In the following article, we cover the installation of NixOS, a Nix-based Linux distribution.
What is Nix
Nix is a functional package manager. Below are the three main benefits of using Nix compared with a traditional package manager:
- Nix brings reliability: installing or upgrading one package don’t break other packages. It ensures that no package is inconsistent during an upgrade. Roll back to previous versions is possible.
- Nix brings reproducibility: packages are built by Nix in isolation from each other. This ensures that they are reproducible and don’t have undeclared dependencies, so if a package works on one machine, it works on another.
- Nix is declarative: Nix makes it easy to share development and build environments for projects, regardless of what programming languages and tools are used.
With Nix, files are related with symlinks. When a package is installed, symlinks point to a location inside the Nix store directory, located in /nix/store
. When upgrading a package, the new package files are extracted in a different location (no overwriting), the symlinks point then to the location of new files.
Usage of symlinks to refers to packages have some advantages:
- No risk of corruption between dependencies: multiple versions of the same dependency can be installed
- Less storage requirement: the same version of a dependency is not duplicated
The upgrade process of a package creates what Nix calls a generation. It is possible to roll back and to roll forward through the previous generations. This leaves the system fully functional because one can always roll back to a previous generation. It is possible to save and keep as many generations as wanted. The downside of this is the hard drive space used to store the generations, but it is possible to clean out old generations.
Nix deployment
Nix can be deployed on an existing operating system, either Linux or macOS, or using NixOS which uses it from the ground up to create a Linux system.
Deployment through NixOS
NixOS is a Linux distribution built on top of Nix. The installation of NixOS share the steps of an alternative Linux distribution: partitioning and formatting of the disk before installation of the operating system. The official documentation gives steps to follow to deploy Nix through NixOS installation.
Deployment on an existing operating system
Nix is supported on Linux (i686, x86_64, aarch64) and macOS (x86_64, aarch64). Below are the commands to install Nix:
-
Linux
-
MacOS:
sh <(curl -L https://nixos.org/nix/install)
Follow the Official documentation for more about installation on an existing operation system.
Usage of Nix
User Environment
A User Environment is a set of active applications. Different users can have different environments and individual users can switch between different environments. ~/.nix-profile
is a symbolic link to the current user environment.
Managing a user environment is done either via declarative configuration using Home Manager or via imperative operations using nix-env
commands.
Home Manager
Home Manager is the preferred way to manage user environments. It allows declarative configuration of user-specific packages and files in the home directory. It is installed via the commands:
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-manager edit
The command home-manager edit
installs Home Manager, initializes and exposes the Home Manager configuration file located at .config/nixpkgs/home.nix
.
Whenever something changes in the Home Manager configuration file, the command below builds and activates the configuration for the user.
Below is an edited version of the file home.nix to install the package firefox
and to configure git
.
config, pkgs, ... :
home.username = "florent";
home.homeDirectory = "/home/florent";
home.packages = [
pkgs.firefox
];
programs.git =
enable = true;
userName = "Florent";
userEmail = "[email protected]";
;
home.stateVersion = "22.05";
programs.home-manager.enable = true;
Note, alternative installation methods integrate Home Manager with the NixOS and nix-darwin configuration. This is how we deploy our systems. Follow the official documentation for more details.
Nix imperative operations: nix-env
User environment, including package installation and removal, can be managed with the nix-env
commands. Below are some of the most useful commands:
nix-env -iA <nixpkgs.pkg-name>
-
To uninstall a package:
-
To upgrade a package:
nix-env -u <some-packages>
Example: installation of virtualenv
with Nix
Here are the steps to install the package virtualenv
using the Nix package manager.
-
Search for
virtualenv
using thenix search
command:nix search virtualenv warning: using cached results; pass '-u' to update the cache * nixpkgs.pew (pew-1.2.0) Tools to manage multiple virtualenvs written in pure python * nixpkgs.python38Packages.pytest-virtualenv (python3.8-pytest-virtualenv) Create a Python virtual environment in your test that cleans up on teardown. The fixture has utility methods to ins> * nixpkgs.python38Packages.tox (python3.8-tox-3.23.0) Virtualenv-based automation of test activities * nixpkgs.python38Packages.virtualenv (python3.8-virtualenv) A tool to create isolated Python environments * nixpkgs.python38Packages.virtualenv-clone (python3.8-virtualenv-clone) Script to clone virtualenvs * nixpkgs.python38Packages.virtualenvwrapper (python3.8-virtualenvwrapper) Enhancements to virtualenv * nixpkgs.python39Packages.pytest-virtualenv (python3.9-pytest-virtualenv) Create a Python virtual environment in your test that cleans up on teardown. The fixture has utility methods to ins> * nixpkgs.python39Packages.tox (python3.9-tox-3.23.0) Virtualenv-based automation of test activities * nixpkgs.python39Packages.virtualenv (python3.9-virtualenv) A tool to create isolated Python environments * nixpkgs.python39Packages.virtualenv-clone (python3.9-virtualenv-clone) Script to clone virtualenvs * nixpkgs.python39Packages.virtualenvwrapper (python3.9-virtualenvwrapper) Enhancements to virtualenv
The search result offers several options to install virtualenv. We selected
nixpkgs.python38Packages.virtualenv
for the following commands. -
Install
nixpkgs.python38Packages.virtualenv
- Option 1: using
nix-env
command:
nix-env -iA nix-env -iA nixpkgs.python38Packages.virtualenv
-
Option 2: using Home Manager
The content of the Home Manager configuration file includes:
config, pkgs, ... : ... home.packages = [ ... nixpkgs.python38Packages.virtualenv ... ]; ...
To apply the Home Manager configuration:
virtualenv
is installed. Below are the commands to create and activate a new python environment namedmyPythonEnv
:virtualenv myPythonEnv source myPythonEnv/bin/activate
- Option 1: using
Generation
Every time a nix-env
operation is done, a revision of the user environment called generation is newly created. Some commands associated to generation:
-
To list generations:
nix-env --list-generations
-
To switch to a specific generation:
nix-env --switch-generation <generation-number>
-
To remove specific generations:
nix-env --delete-generations <generation-numbers separated by space>
-
To roll back to the last
nix-env
command (to the last generation): -
To delete older generations:
nix-env --delete-generations old
Profiles
Profiles are groups of generations so that different users don’t interfere with each other if they don’t want to. Profiles and User Environments are Nix’s mechanisms to allow different users to use different configurations.
Derivation
A Derivation is a Nix expression describing everything that goes into a package build action (build tools, dependencies, sources, build scripts, environment variables). It is anything needed to build up a package.
Channels
A channel is a git repository containing a list of packages. Official channels are verified by Nix. Some commands associated to channels:
Garbage collection
When a package is uninstalled, it is not actually deleted from the system even if no user refers to it. By this way, it won’t be re-downloaded if it happens that you need it again. Unsued packages are be deleted with the garbage collector command:
Conclusion
Nix is a cross-platform package manager managing dependencies by itself efficiently. It simplifies the process of managing a user environment via a declarative way and makes easy sharing of a user environment. However, it comes with a steep learning curve. In my experience, learning its usage was worth it.