How to get (in)to Nix: resources, tools, and personal experience.
Nix is known to be hard to learn, and the official documentation can be difficult to navigate. I’ve been playing around with it for two years, following a plethora of guides and blog posts to implement this and that. I don’t see myself as a Nix expert for anything, but I’ve gathered a lot of resources over time.
I won’t talk about “Why you should use Nix” as there are plenty of posts about it, and if you are here, you’re probably at least curious about it. In this post, I go over the different use cases I’ve looked at, and redirect the reader to relevant resources on the subject. Let’s not reinvent the wheel.
This is an opinionated guide referring to sometimes opinionated resources. Therefore, it probably won’t be representative of a ground-truth about Nix, but I’ll try to follow where (at least part of) the community goes.
The official documentation for Nix as often regarded as difficult to navigate, and sometimes too old. It is, however, a great way to familiarize with Nix’ core concepts, and the motivation behind it. I would definitely advise starting there.
Nix’s official documentation is structured around three manuals, one for each application of Nix. These manuals should remain the reference about Nix. I advise readers to start by going through the first two before digging too far into Nix.
Nix is a package manager that focuses on reproducible and declarable packaging. Packages are described using the Nix Expression Language, a pure, functional, programming language. Both are described in the Nix Manual. However, I would advise against spending too much time on the old set of
nix-*commands, as they’ll be progressively replaced by the more modern
Nixpkgs is one of the biggest set of packages around. It uses the Nix Expression Language to package binaries, scripts, and libraries. The Nixpkgs Manual provides details on how to download and build packages from Nixpkgs, as well as how to package unavailable softwares and expends on Nixpkgs’ features.
NixOS is a Linux distribution based on Nix and Nixpkgs. It allows users to declaratively define the expected state of their distribution, and generate an image, a container, or a filesystem that respects this definition. The NixOS Manual provides details on the NixOS-related configuration option, and overall usage. Since it focuses on the distribution, I would not advise reading the NixOS Manual, unless you have interest in using the distribution, as it adds another layer of complexity. It is easier to comprehend if you are already familiar with Nix.
About Nix flakes >
Starting with Nix 2.4, Nix ships with flakes, a new way to pin Nixpkgs revisions and specify packages dependencies. It’s often considered as the future of Nix. Many resources now deem channels (the old way) deprecated, and advocate for new users to focus solely on flakes. I personally have migrated all my workflows to flakes, and would not go back.
However, flakes are still officially considered as experimental.
The official documentation, especially the Nix and Nixpkgs Manual, is often criticized for the lack of resources on flakes and the fact it still uses channels everywhere.
The reference for the
nix command (in the Nix Manual) contains details about flakes and how they should be used.
This is, AFAIK, the only official resource.
The official learning portal also has smaller guides for specific aspects of the environment, such as how to pin Nixpkgs, how to use Nix for developer environments or to build Docker images.
The official team also maintain useful tools:
The Package Search allows users to search the immense collection of Nixpkgs, among the different releases and channels.
The Option Search indexes the available options in official NixOS modules, alongside their documentation. There are several community efforts to provide unified interfaces to search options in NixOS, as well as other similar tools, such as Home-Manager or Nix Darwin (see below).
Due to how rapidly the ecosystem evolves, the official documentation sometimes seems to lack content, features, and tools. The evergrowing community stepped in to fill the gaps. Here are the most interesting semi-official or fully community-driven resources.
Nix Pills is a semi-official introduction to Nix that originally was a series of posts by Luca Bruno, between 2014 and 2014. It’s often referred to as The classic introduction to Nix. Since 2017, it is ported to the official website and kept updated. It’s a perfect resource for newcomers as it covers, with simple words, most of the concepts behind Nix and it’s language.
Words of warning >
While you probably won’t encounter mistake in the Pills, they might feel outdated as they don’t mention flakes. If you start with flakes (which you should!), a lot of them might be irrelevant. If you don’t want to read all of it, you can probably skip pills 2–3 and 10–14, as they dig into packages the old way. It remains worth reading, though!
The official Discourse server for the community allows anyone to get help on everything Nix-related. I consider it as a semi-official resource, as while it’s hosted by the NixOS organization, it’s populated by users. It’s a nice place to search for common errors and/or objectives. If you want to do something, it’s likely that someone else did too.
The NixOS Wiki is an attempt to make the documentation more searchable and interactive. It works like most wikis, and often seem more up-to-date than the official docs. Contributors add code examples that you can reuse in your own projects. This is a great resource when you’re familiar with the ecosystem, but want to dig a specific aspect.
Inspired by other “A tour of *” series (A tour of Go, A tour of Rust, …), A tour of Nix provides a set of interactive tutorials where your can run Nix commands in a web-based playground. I’ve never used it myself, but it allows you to play around without installing the tools.
nix.dev is an opiniated guide to Nix by Domen Kožar that aim at completing the official documentation. I wouldn’t advise readers to use it as their main resource, however, as it does not cover flakes. There are still interesting articles, like on shell environments, continuous integration, and deploying NixOS hosts.
Zero to Nix is a very recent resource that aim at filling the gap between the official resources and the state of the community. It is very opiniated, as it focuses on flakes solely, and considers channels and other legacy nix commands as deprecated. This resource has multiple benefits:
- It starts “from scratch”, targeting a very wide audience. You could technically use it to learn Nix without prior knowledge.
- It focuses on flake, that many consider the future of Nix.
- It links a lot of other resources, both from official and community-driven documentation.
- It is done by Determinate Systems, where a lot of people that are active in Nix work, including Eelco Dolstra, one of the authors of the original papers on Nix and NixOS.
Tweag’s introductional series on Nix flakes is a fantastic resource to discover flakes. It was also written by Nix founders (hey Eelco!). You need basics on the Nix Expression Language to fully understand the given examples. Tweag’s blog overall is a great resource for everything Nix related.
Ian Henry’s How to Learn Nix is another blog series on Nix, but with a very different approach. The reader follows Ian, going through the Nix manual as he tries to grasp how Nix does things, instead of just how to do stuff with Nix. As we go through the articles, we dive into Nix’s internals. This one of my personal favorites, as it is well written, often amusing, and goes deep into the concepts. As the author puts it, a “series of blog posts about someone you’ve never met reading a manual about an obscure piece of technology you’ve barely heard of? It doesn’t get much better than that.” However, for most users, it might be overkill.
awesome-nix is yet another “curated list of awesome resources”, this time about Nix. Like other lists of this new genre, it’s very subjective and kind of vague; yet you might find what you were looking for.
Alongside these resources, the community also maintain useful tools for digging through Nix.
MyNixOS is intended as a configuration-assistant tool for Nix shells, NixOS, and Home-Manager. However, it’s also very useful to search options and packages for all supported platforms. I personally rarely use it, but see the benefits.
Cachix is a company-sponsored cache management tool to build and maintain your own Nix cache server. Especially, Cachix hosts cache servers for a lot of community projects, like nix-community’s.
Then how to start?
Even with this list, reading through all of it would take a lot of time. If you just want to get familiar with the technology, you can focus on the following:
Start with Determinate Systems’ Zero to Nix tutorial. Embrace flakes and the Nix 2.0 CLI, as it is taught in this series. Follow the links to other concepts if you’re curious, but skip anything mentioning channels for now, as (1) you probably won’t need it, and (2) it might conflict with stuff your read.
Go over the Nix manual, especially the sections about the language syntax. Being able to understand the language is key for digging into it afterwards.
Play around! Install Nix (if you didn’t already), and try installing a package, or writing a shell environment.
While I would still recommend reading through at least one of the resources I previously mentioned, you can also start with a specific objective, and learn Nix along the way. Therefore, you will find hereafter specific resources depending on your objective to “streamline” your learning.
Reproducible development environments
Probably one of the main use case for Nix is the creation of reproducible development environments. Let’s look at some situations where you could benefit from Nix.
Say you are a developer in a team, working on some Python project. To make things easier for your colleagues, you commit your
requirements.txt. After installing all off your dependencies on their system, they are still unable to run your code, as it fails with deprecation warnings.
Granted, this could mostly be solved by using Poetry (or other equivalent Python package manager) and versioning the lock file. However, Nix’ approach is language-agnostic.
Say you work on deployment, and that you split the workload with you colleagues. When you ran the Ansible recipe that your colleague built and tested, it failed, leaving you with a broken environment.
Say that you develop a binary application that is dynamically linked. You are forced to push a quick patch on the remote because of a bugfix recently added to
glibc, that you know about because you use a rolling release Linux distribution. Your co-workers do not have the
glibcfix yet, and cannot run the new version.
These examples of misfortune are all caused by version mismatch, happening at different level in the tool chain. Some situations can be fixed, like the Python version, by adding other tools to the mix, but Nix offers a do-it-all solution.
If you are interested in reproducible development environments, have a look at the following resources:
This article from Zero to Nix’s quick start guide focuses on using flakes for development environments. You’ll learn how
nix develop, the command to instantiate shells, can be used to setup development environments that are independent of the host system. If it’s the very first resource about Nix your read, go back to the first sections of the quick start guide.
This article from nix.dev presents the old way, without flakes. It sometimes represents a simpler alternative as it does not require users to enable any feature that is labeled as “experimental”, and the syntax a
shell.nixfile is a tiny bit simpler than a flake.
This other article from Martin Myrseth takes a look as Nix and NixOS as a development environment. Most of it actually does not require NixOS specifically, and is therefore more relevant here. It differs from the other by going way deeper in the language and the functioning of a flake, with digressions about useful community libraries like flake-utils. It also has a realistic use case with an environment for a full stack application, which implies multiple languages and tool stacks.
The principles behind development environments can easily be extended to any kind of shell environments.
For instance, RedNix (a NixOS-based distribution for penetration testing and security) provides
devShells for different categories of security tools.
This can be adapted to other use cases, as long as one of your activities requires having access to a set of packages and configurations in your shell.
You can make it more permanent by looking at profiles.
While Nix can theoretically be installed on any Linux distribution (as well as on MacOS), users might be reluctant to install a daemon running in root to use it. There are community efforts to make nix portable and self-contained, but these are very niche projects.
About right management >
You need administrator rights to install Nix, as it requires mounting a dedicated volume at
/ for the nix store (
/nix/store)—where derivations, sources, and binaries are stored—, and running a root daemon for multi-users installations.
However, once it is done, every other operation can be done at user-level without particular rights.
Finally, you can have a look at devenv.sh, a do-it-all utility that aims at streamlining the entire DevOps process using Nix.
It is especially geared towards novices, and does a lot of stuff to make Nix’s ecosystem more accessible.
Therefore, I would recommend against using it, as it does a lot of abstraction that hides how Nix works.
Furthermore, if you use flakes (which you should), a
devenv.nix file in your project directory will not do much that you cannot do with your
flake.nix if you know the syntax, such as shell environments, build recipes, and
It remains a great tool if you do not want to learn about Nix, or for user service management in your environment.
Tidying your $HOME
Probably the second most important advantage to Nix’s ecosystem is its declarative package and configuration management system, via NixOS. However, it is impossible to enjoy (some of) the advantages of NixOS on other distributions.
Home-Manager is a community project to port NixOS’ philosophy to the user’s home directory and user services.
Originally made by Robert Helgesson, the project has since been transferred to the
nix-community GitHub organisation.
The latter is a semi-official organization that works alongside the official NixOS team to maintain community projects and resources around the entire Nix ecosystem.
Home-Manager has its own “official” documentation, but it is quite sparse. Some of the resources that we have already covered address Home-Manager and its usage, but the following are specific to it.
The “official” documentation focuses on Home-Manager’s installation, and gives a few configuration examples. It is not very dense, but is definitely the first thing to read if you are interested in Home-Manager. Note that since the overall structure and usage of the Home-Manager—provided modules are very close to NixOS’, having experience with NixOS is definitely an advantage.
The Configuration Options annex in the official documentation is a great resource to configure the official provided modules. It lacks a search engine, but is probably the most up-to-date documentation available.
Home-Manager Options Search is a community-made search engine, independent from the “official” Home-Manager development team. It goes through Home-Manager module options to provide the option name (and parent if any), a description, and the expected value type.
Declarative System Configuration
Finally, NixOS is a Linux distribution based on Nix.
The rationale behind NixOS is the same as Nix’: the package manager generates build output in the Nix store, and simlinks them to the filesystem. With NixOS, the same is applied to configuration files, eg. most of your
/etc directory will be simlinks to
To learn about NixOS, the best way remains to play with it.
The official NixOS Manual and Zero-to-Nix’ dedicated page are great general resources on that regard, as mentioned above.
Now, NixOS is full of resources, and there are a lot of documentation and blogposts to enable this and that. I’ll give a list of use cases here, and let the reader select those that seem relevant.
Specializations are a relatively recent feature that allows you to build multiple boot entries each time you (re-)generate your system. For instance, you can have one with loaded Nvidia drivers, and the other with your integrated GPU’s ones, to boot on one version depending on your workload. This article from Tweag is a great starting point.
About boot entries >
NixOS generates boot entries each time you build a new generation. A generation is a set of packages and configuration files that are built together, and that can be booted together. Every time you run
nixos-rebuild, a new generation is created, and a new boot entry is added to your bootloader. This makes it virtually impossible to break your system, as you can always boot on a previous generation.
Nix(OS) is also very useful to create minimal container images, as you can build a container image containing only the closure required by your binary. You can either use Nix tools, such as
pkgs.dockerTools.buildLayeredImageas shown in the Manual, or use the more classical Dockerfiles to build your Nix-based images, like in this blogpost that uses
About closures >
In programming languages, a closure is the scope of a function, ie. the set of variables that are accessible from a function, as well as the function itself. In Nix, everything is stored in the
/nix/store, so the closure of a given store path is the set of all references to other store paths that it contains.
More specifically, for a package in the store, the closure of a derivation is the set of all store paths that are required to build it, and the closure of its output path (eg. the compiled binary) is the set of all its runtime dependencies. The Nix Manual has a glossary that can be referred to for details on the Nix vocabulary.
NixOS is especially useful to administrate a fleet of devices, as you can reuse your configuration to have the same environment on all your machines. If you sometimes deploy machines “on-demand”, you might also be interested in tools to manage and update your fleet, such as
deploy-rs. Note that
nixos-rebuild(the command to build and activate your configuration) already supports remote deployment, as explained in this article.
In terms of security, NixOS has some advantages, especially in multi-user installations. In fact, in such configuration, each user has unprivileged access to
/nix/store, without impacting the others. No need for root’s rights. The store is in read-only, making it difficult for a third-party software to modify sensitive files. You will find some details on the way its works in the corresponding manual chapter. I also recommend this article from Xe Iaso about securing Nix; this website has also a lot of posts on that subject.
I have developed a tendency to use Nix everywhere (which you will too!), but my main use case remains development environments. As I work on a lot of different projects, I use Nix and Direnv to instantiate environments dynamically when I enter a project’s directory, without having to install anything globally. I also use Nix to manage my dotfiles (via Home-Manager), and to deploy and manage Linux systems (via NixOS). A such, I write a lot of (ugly) Nix code, and I have a few tools that I use to make my life easier. Here is a non-exhaustive list of them.
Direnv is not a Nix tool by design. It’s meant to load and unload environment variables dynamically when you enter and exit a directory. However, its integration with Nix (via
nix-shellor flakes) makes it a key companion for a Nix user. With compatible flakes, it will run
nix developautomatically when you open your project’s directory, making all your dev dependencies available. Nix Community maintains an improved version of Direnv’s Nix integration which provides persistent caching, resulting in faster shell loading times.
flake-utilsis a pure Nix library that provides helpers to write flakes. The most used ones are probably
lib.eachDefaultSystem, which allow you to write a single expression that will be evaluated for each system you want to build for. It is especially relevant when writing packages definitions or shell environments, as you can your definition once, without thinking about the target system. However,
flake-utilsis sometimes criticized for the way it abstracts Nix concepts, making it mistake-prone for newcomers. Fernando Ayats recently wrote an article on that subject, advocating against using
flake-utilsin favor of more explicit Nix code, or existing alternatives such as
flake-parts. I personally use
flake-utilsin my projects, but I’m not sure whether I would recommend it to newcomers.
nilis a state-of-the-art implementation of LSP (Language Server Protocol) for Nix, which provides autocompletion, syntax checking, and more. It is still in development, but already usable. It integrates especially well with VSCode via Nix IDE (the most advanced Nix plugin for VSCode), but can also be used with other editors such as Vim or Emacs.
nixpkgs-fmtis a formatter for Nix (no way…). It has been made to standardize the way packages are written in Nixpkgs, but can be used on any Nix file. Nix IDE integrates well with it, and can format your files on save.