Intro to Nix Package Manager – A purely functional package manager

In this article, we’ll be talking about the Nix package manager. If you are reading this on any Linux distribution, you probably know what a package manager is. But for starters, a is package manager is software that is used to install, remove, upgrade the packages on a device. However traditional package managers like apt and Pacman has multiple flaws which make them unreliable to be used in environments that need highly stable systems such as servers.

Nix however is designed to be a reliable and reproducible package-management system that solves the common problems posed by traditional package managers. But to understand the solution, we have to understand the problem first.

Drawbacks of traditional package managers

Changes can’t be undone: Traditional package managers like apt or Pacman install all packages globally in /usr/local/bin. If you update or reconfigure any package, it simply updates the corresponding file in /usr/local/bin thus changing the state of that package permanently with no way to revert back to an older version.

Updates are not atomic (instant): During any update, the changes to the packages are applied throughout the duration of the update. c. This means that if the upgrade to a new configuration is interrupted — say, the power fails halfway through — the system will still be in a consistent state: i, it can potentially break the whole system with half updated drivers and half-installed dependencies.

Dependency Hell: This problem even has a whole Wikipedia page dedicated to it. Suppose you have to install a package A which is dependent on package B and package C . B and C in turn are dependent upon two different versions of D. This is a problem because traditional package managers cannot use two versions of the same package at a time. So in this case we can either install B or D but not both, and thus we cant install A. This particular style of the problem is called diamond dependency conflict.

Diamond Dependency Conflict
Diamond Dependency Conflict

There are many other dependency problems like circular dependency conflict and linear dependency conflict all arising from the fact that traditional package managers cannot install two versions of the same package, side by side.

How Nix solves these problems

As mentioned in the title, Nix is a purely functional package manager. In simple terms what this is means that all the packages built by Nix have a unique hash attached to them which is derived by the dependencies of the package.

Think of it as a machine that takes all the inputs related to a package i.e. its dependencies, the versions of all dependencies, C/CXX flags, sources, config files, environment variables, external patches, etc. and then outputs an expression (Nix Expression) which then produces a package with a unique hash which cannot be changed and stores it at /nix/store/some-unique-package-name. For example, the path for my bash shell is

/nix/store/hrpvwkjz04s9i4nmli843hyw9z4pwhww-bash-4.4-p23 

Recompiling the package by changing dependency version or using different dependency will result in a totally different package with a different hash.

Nix Schematic

Multiple versions: Because of the hashing scheme, different versions of a package end up in different paths in the Nix store, so they don’t interfere with each other. Revisiting the problem of dependency hell, since the two versions of package D are totally different packages now, you can build package B using one version and package C using another without any conflict.

Atomic changes and rollbacks: Since the updated packages are totally different packages from the existing ones, the old packages will not be deleted but the new packages will simply be symlinked over the older ones. Since there is no change being done to the packages currently being used, it will not break the system if the update process is interrupted in between. The actual change i.e. linking new versions of packages over the older is done in an instant (atomic).

Since the old versions of packages are still there, this means that you can rollback your machine to the old packages anytime.

if you are thinking that this whole multiple version shebang will eat up too much space, you can always run a garbage collection command which will delete your unused packages.

Reproducibility: Through Nix, it is very easy to replicate development environments. All you have to do is check the configuration file for any package which mentions everything about the package, copy it over to the system, and rebuild the package with the same dependency versions and environment variables. And it will be very clear if the two environments are consistent or not since all the packages on the replicated environments should have the same hash as that of the original.

How to Install Nix

If you are excited about Nix and want to try Nix out but don’t want to leave the comfortable distro that you spent months setting up, I have good news. You can install the Nix package manager on any Linux distribution with just a single command. Just execute the following command in your terminal.

$ curl -L https://nixos.org/nix/install | sh

However if you want the whole experience you can always download and install NixOS which uses Nix not just for package management but also to manage the system configuration (e.g., to build configuration files in /etc). This means that it is easy to roll back the entire configuration of the system to an earlier state.

How to use the Nix package manager?

Let’s get started with the usage of the Nix package manager for your Linux distribution.

1. Profiles

Different users on Nix can have different set of packages installed and have different configurations. Any changes done in on profile does not effect any other profile since they are sand-boxed.

2. Channels

A channel is a git repository list of packages (and their definitions) officially verified by Nix. This is similar to the concept of repositories in Ubuntu/Debian/Arch. There are multiple channels based on different levels of verification. You can find the list of channels here.

List current channels:

$ nix-channel --list

Subscribe to new channels:

nix-channel --add https://some.channel/url my-alias

Remove channels:

nix-channel --remove channel-alias

Update channels:

nix-channel --update channel-alias

Update all channels:

nix-channel --update

3. Searching for packages

To search for a package in the current list of channels:

nix search <pkg-name>

It will list a bunch a applications which contain the keyword in <nixpkgs.pkg-name> format.

However you can also go the online Nix store and search for the package with instructions on how to install it.

Online Nix Package

4. Installing packages

To install any package in the current profile , use

nix-env -iA <nixpkgs.pkg-name>

The “-A” flag enables us to choose a specific channel to download the package from. If you want to install from default channel, use

nix-env -i <pkg-name>

5. Uninstalling packages

To install any package in the current profile, use

nix-env -e <pkg-name>

6. Upgrading packages

To upgrade any specific package, use

nix-env -u subversion

To upgrade all the packages in the profile, use

nix-env -u

7. Rollbacks

You can rollback you last nix-env command by using

nix-env --rollback

Every time you perform a nix-env operation, a new user generation of the user-enviroment is created. For example, when we install tdesktop a new generation got created. You can list all generations using

nix-env --list-generations

and switch to a specific generation using

nix-env --switch-generation <gen-number>
Nix Generations
Nix Generations

8. Garbage removal

You can delete older generations using

nix-env --delete-generations old

Do delete specific generations, use

nix-env --delete-generations 1 2

Conclusion

Congratulations. Now that you understand Nix and basic package management in Nix, you wont have to fear the dreaded dependency hell and new updates breaking your system. To learn more about Nix you can use the official Nix Wiki. Have fun!