<commit_before>---
title: My experience with NixOS
tags: [linux, nixos, review]
---

NixOS is a novel Linux distribution started in 2003; it's built upon the [Nix
package manger](https://en.wikipedia.org/wiki/Nix_package_manager) which
provides a [functional, declarative
approach](https://en.wikipedia.org/wiki/NixOS#Declarative_system_configuration_model)
to package management. NixOS takes the direction of Nix, which can run on any
Unix-like distro (including OS X), and continues further to
allow control over the entire OS, from the file system to various services like
SSH and HTTP, using the same declarative syntax. This means an entire NixOS
setup, including all services, packages installed, and even configurations, can
be represented in Nix configuration files and, potentially, stored some place
like Github.

Similar to how software like
[PlayOnLinux](https://en.wikipedia.org/wiki/PlayOnLinux) works, where each
program installed has its own WINE context and is stored completely separate
from all other programs (for ideal stability), Nix takes a
completely revised approach to storing both binaries and libraries in the Linux
file system. In functional programming terms, the typical file system of
a Linux machine is global, mutable state. Everything lives in one place, either
`/usr` or `/usr/local` or similar. This means it's very difficult to, for
example, have several versions of the same library installed at once. It's also
difficult to atomically upgrade and revert entire states of the file system.

As a novel way of avoiding [dependency
hell](https://en.wikipedia.org/wiki/Dependency_hell), Nix stores all installed
packages, including system libraries, in `/nix/store/<hash>-package-version`
(example: `/nix/store/dpmvp969yhdqs7lm2r1a3gng7pyq6vy4-subversion-1.1.3`). Each
package's dependencies are defined explicitly and Nix uses symbolic links to
ensure that, when using a given package, all of its dependencies are made
available. More info is available in the [Nix
manual](http://nixos.org/nix/manual/).

### Why bother?
At this point, it may not be clear why NixOS is worth exploring. To anyone who
has used [Chef](https://en.wikipedia.org/wiki/Chef_%28software%29), or similar
software, to describe the construction of machines, especially for replication in
clusters (using, say,
[vagrant](https://en.wikipedia.org/wiki/Vagrant_%28software%29)), NixOS provides
even more control over the exact state of the machine. Furthermore, it doesn't
rely on wrangling existing distros (like Ubuntu), though this can be considered
a drawback. The biggest win is, since the entire system is controlled by Nix
files, and every bit of configuration and every package is described explicitly,
with all of its dependencies and environment, you can turn any NixOS machine
into something complete different instantly and without rebooting. Let's get to
some examples.

[My Nix files](https://github.com/jeaye/nix-files) describe the setup I was
building, which is my "desktop" workstation where I do primarily C++ and Clojure
development. I use Vim, watch movies with mplayer, listen to music with cmus,
etc; all of this is described within these configuration files. The nice thing
about declarative configuration is that you describe *how the system should look
when it's ready* not *how it should get there*.

#### Describing a NixOS system
If you're doing it right, everything you need is in the form
of Nix files. We can start with [describing
GRUB](https://github.com/jeaye/nix-files/blob/master/grub.nix), instead of using
the typical grub commands and mutating `/etc/grub.d` and `/boot/grub/`. After
that, we might describe our [network
configuration](https://github.com/jeaye/nix-files/blob/master/network.nix),
which includes a firewall. We can describe [each
user](https://github.com/jeaye/nix-files/blob/master/user.nix) and the groups
they're in, the permissions they have, their shell, home directory, etc.

Once the base system is setup, we can describe [how we want X to
behave](https://github.com/jeaye/nix-files/blob/master/x11.nix), which even
includes installing proprietary drivers and setting up kernel modules, if
needed. From there, specifying any number of packages we want and any
configurations we want for them is entirely up to what's described in the Nix
files.

Once you're in a NixOS machine, you can change your configs and then just run
`nixos-rebuild switch` and Nix will realize everything you described, even if it
means building a new kernel, bringing in new software, dependencies, upgrading
something, or performing big changes like switching from KDE to GNOME.

An example of just how simple something like a kernel upgrade can be: [this
commit upgrades my machine to Linux
4.2.x](https://github.com/jeaye/nix-files/commit/03fe9397337d13b65700b555525de047760314a5).
No longer should you have to waste time reconfiguring machines to be similar to
other machines you've setup.

### My thoughts
Though it may sound like I'm just trying to sell NixOS here, I'm not actually
using it anymore. Why not?  First, I want to say more about what I love with
regard to Nix and NixOS.

* Easy install of any packaged software (steam, skype, etc)

  * By just describing that the package should be installed, in your Nix files,
    and telling Nix to realize what you described, you can completely rework
    your system

* Seemingly large changes, like a kernel update are often a one-liner
* Your entire system is stored in configuration files which can easily be put
  onto Github

  * Once you describe a machine, you can replicate it anywhere. If you lose that
    machine, the configs will bring you back to where you need to be.

* Upgrades are atomic and you can rollback any changes

  * By default, when you tell NixOS to realize your configs, it takes a snapshot
    of your current configs and updates GRUB so you can even choose previous
    setups at boot.

* Installation is a breeze

  * I installed NixOS from my existing Slackware install!

* The IRC channel on Freenode, #nixos, is quite active and helpful

With all of that said, I found that NixOS isn't suitable for my development
workstation. I spent a great deal of time compiling software which has various
dependencies. In NixOS, in order for those dependencies to be available, one
needs to use `nix-shell` with some Nix file which describes the dependencies of
that shell (boost, SDL, etc). Along with that, compiling arbitrary software
which functions as a plugin of Nix-packaged software can be a real pain in the
ass (namely Vim plugins with compiled components). Here are some noted
drawbacks.

* nix-shell is needed to build anything sane

  * One needs to describe every single package which is required, otherwise
    NixOS won't have them linked into the current environment. Unfortunately,
    even in they are linked in, I still ran into a plethora of issues with
    software like CMake not being able to find the right packages. This was my
    biggest issue.

* The documentation is either awful or nonexistent

  * NixOS isn't that new, but it really only has a manual. Unfortunately, the
    manual doesn't even cover all of the aspects. Some are in the man pages,
    others exist in various blogs, and others are only in the minds of those
    dwelling on IRC. Getting going with NixOS is a difficult experience; trying
    to use NixOS for anything other than exactly what's intended is also going
    to be painful.

* nixpkgs is, often times, the only useful resource

  * Due to the complete lack of useful documentation on various packages, one
    typically needs to browse [nixpkgs](https://github.com/NixOS/nixpkgs) in
    order to know the configuration options which are actually allowed for a
    given package.

* There is no startx

  * On both Slackware and Arch, I boot into multi-user mode and manually run
    `startx` when I'm ready for a graphical session. This is impossible in
    NixOS, due to there being no `startx`. A small annoyance, sure, but it means
    I need to put up with some DM. Worse, the default NixOS DM, Slim, is
    abandoned and lacks common functionality like reading `~/.xinitrc`.

* Hard to debug

  * Due to how foreign and opaque the NixOS file system is, with symbolic links
    up the wazoo, finding out why a program isn't running is very difficult.

### Summary
I would absolutely consider using NixOS for a non-development machine. I'm very
much considering moving http://jeaye.com from DigitalOcean to Linode, which will
allow me to use NixOS. Being able to describe complex setups like a postfix +
dovecot mail server, for example, using Nix files and being able to reproduce
that machine once written would really give me some peace of mind as a
administrator.

For those interested, there is also a newer project,
[GuixSD](https://en.wikipedia.org/wiki/Guix_System_Distribution), which uses
Guix, a fork of Nix. GuidSD tries to accomplish very similar tasks as NixOS; the
key difference is the use of Scheme instead of Nix's purely functional language.
From what I've read, GuixSD is much younger and supports fewer packages.
Furthermore, since it's part of the GNU project, you can expect that it would be
very partial toward free software.<commit_msg>Clean up the nixos post<commit_after>---
title: My experience with NixOS
tags: [linux, nixos, review]
---

NixOS is a novel Linux distribution started in 2003; it's built upon the [Nix
package manger](https://en.wikipedia.org/wiki/Nix_package_manager) which
provides a [functional, declarative
approach](https://en.wikipedia.org/wiki/NixOS#Declarative_system_configuration_model)
to package management. NixOS takes the direction of Nix, which can run on any
Unix-like distro (including OS X), and continues further to
allow control over the entire OS, from the file system to various services like
SSH and HTTP, using the same declarative syntax. This means an entire NixOS
setup, including all services, packages installed, and even configurations, can
be represented in Nix configuration files and, potentially, stored some place
like Github.

Similar to how software like
[PlayOnLinux](https://en.wikipedia.org/wiki/PlayOnLinux) works, where each
program installed has its own WINE context and is stored completely separate
from all other programs (for ideal stability), Nix takes a
completely revised approach to storing both binaries and libraries in the Linux
file system. In functional programming terms, the typical file system of
a Linux machine is global, mutable state. Everything lives in one place, either
`/usr` or `/usr/local` or similar. This means it's very difficult to, for
example, have several versions of the same library installed at once. It's also
difficult to atomically upgrade and revert entire states of the file system.

As a novel way of avoiding [dependency
hell](https://en.wikipedia.org/wiki/Dependency_hell), Nix stores all installed
packages, including system libraries, in `/nix/store/<hash>-package-version`
(example: `/nix/store/dpmvp969yhdqs7lm2r1a3gng7pyq6vy4-subversion-1.1.3`). Each
package's dependencies are defined explicitly and Nix uses symbolic links to
ensure that, when using a given package, all of its dependencies are made
available. More info is available in the [Nix
manual](http://nixos.org/nix/manual/).

### Why bother?
At this point, it may not be clear why NixOS is worth exploring. To anyone who
has used [Chef](https://en.wikipedia.org/wiki/Chef_%28software%29), or similar
software, to describe the construction of machines, especially for replication
in clusters (using, say,
[Vagrant](https://en.wikipedia.org/wiki/Vagrant_%28software%29)), NixOS provides
even more control over the exact state of the machine. The biggest win is, since
the entire system is controlled by Nix files and every bit of configuration is
described explicitly, you can turn any NixOS machine into something complete
different instantly, without rebooting. Let's get to some examples.

[My Nix files](https://github.com/jeaye/nix-files) describe the setup I was
building, which is my desktop workstation where I do primarily C++ and Clojure
development. I use vim, watch movies with mplayer, listen to music with cmus,
etc; all of this is described within these configuration files. The nice thing
about declarative configuration is that you describe *how the system should look
when it's ready* not *how it should get there*.

#### Describing a NixOS system
If you're doing it right, everything you need is in the form
of Nix files. We can start with [describing
GRUB](https://github.com/jeaye/nix-files/blob/master/grub.nix), instead of using
the typical grub commands and mutating `/etc/grub.d` and `/boot/grub/`. After
that, we might describe our [network
configuration](https://github.com/jeaye/nix-files/blob/master/network.nix),
which includes a firewall. We can describe [each
user](https://github.com/jeaye/nix-files/blob/master/user.nix) and the groups
they're in, the permissions they have, their shell, home directory, etc.

Once the base system is setup, we can describe [how we want X to
behave](https://github.com/jeaye/nix-files/blob/master/x11.nix), which even
allows installing proprietary nVidia drivers and setting up kernel modules, if
needed. From there, specifying any number of packages we want and any
configurations we want for them is entirely up to what's described in the Nix
files.

Once you're in a NixOS machine, you can change your configs and then just run
`nixos-rebuild switch` and Nix will realize everything you described, even if it
means building a new kernel, bringing in new software, dependencies, upgrading
something, or performing big changes like switching from KDE to GNOME.

An example of just how simple something like a kernel upgrade can be: [this
commit](https://github.com/jeaye/nix-files/commit/03fe9397337d13b65700b555525de047760314a5)
upgrades my machine to Linux 4.2.3.  No longer should you have to waste time
reconfiguring machines to be similar to other machines you've setup.

### My thoughts
Though it may sound like I'm just trying to sell NixOS here, I'm not actually
using it anymore. Why not?  First, I want to say more about what I love with
regard to Nix and NixOS.

#### Pros
* Easy install of any packaged software (steam, skype, etc)

  * By just describing that the package should be installed, in your Nix files,
    and telling NixOS to realize what you described, you can completely rework
    your system

* Seemingly large changes, like a kernel update, are often a one-liner
* Your entire system is stored in configuration files which can easily be put
  onto Github

  * Once you describe a machine, you can replicate it anywhere. If you lose that
    machine, the configs will bring you back to where you need to be.

* Upgrades are atomic and you can rollback any changes

  * By default, when you tell NixOS to realize your configs, it takes a snapshot
    of your current configs and updates GRUB so you can even choose previous
    setups at boot.

* Installation is a breeze

  * I installed NixOS from my existing Slackware install!

* The IRC channel on Freenode, #nixos, is quite active and helpful

#### Cons
With all of that said, I found that NixOS isn't suitable for my development
workstation. I spend a great deal of time compiling software which has various
dependencies. In NixOS, in order for those dependencies to be available, one
needs to use `nix-shell` with some Nix file which describes the dependencies of
that shell (boost, SDL, etc). Along with that, compiling arbitrary software
which functions as a plugin of Nix-packaged software can be a real pain in the
ass (namely Vim plugins with compiled components). This really left me in a
bind, as I wasn't able to freely compile the components I needed in order to do
any actual development.

* nix-shell is needed to build anything sane

  * One needs to describe every single package which is required, otherwise
    NixOS won't have them linked into the current environment. Unfortunately,
    even if they are linked in, I still ran into a plethora of issues with
    software like CMake not being able to find the right packages. This was my
    biggest pain.

* The documentation is either awful or nonexistent

  * NixOS isn't that new, but it really only has a manual. Unfortunately, the
    manual doesn't even cover all of the aspects. Some are in the man pages,
    others exist in various blogs, and others are only in the minds of those
    dwelling on IRC. Getting going with NixOS is a difficult experience; trying
    to use NixOS for anything other than exactly what's intended is also
    painful.

* [nixpkgs](https://github.com/NixOS/nixpkgs) is, often times, the only useful
  resource

  * Due to the complete lack of useful documentation on various packages, one
    typically needs to browse [nixpkgs](https://github.com/NixOS/nixpkgs) in
    order to know the configuration options which are actually allowed.

* There is no startx

  * On both Slackware and Arch, I boot into multi-user mode and manually run
    `startx` when I'm ready for a graphical session. [This is impossible in
    NixOS](https://nixos.org/wiki/Using_X_without_a_Display_Manager), due to
    there being no `startx`. A small annoyance, sure, but it means I need to put
    up with some DM. Worse, the default NixOS DM, Slim, is abandoned and lacks
    common functionality like reading `~/.xinitrc`.

* Hard to debug

  * Due to how foreign and opaque the NixOS file system is, with symbolic links
    up the wazoo, finding out why a program isn't running is very difficult.

### Summary
I would absolutely consider using NixOS for a non-development machine. I'm very
much considering moving [jeaye.com](http://jeaye.com) from DigitalOcean to
Linode, which will allow me to use NixOS. Being able to describe complex setups
like my postfix + dovecot mail server, for example, using Nix files, would
really give me some peace of mind as a administrator.

For those interested, there is also a newer project,
[GuixSD](https://en.wikipedia.org/wiki/Guix_System_Distribution), which uses
[Guix](https://en.wikipedia.org/wiki/GNU_Guix), a fork of Nix. GuidSD tries to
accomplish very similar tasks as NixOS; the key difference is the use of
[Scheme](https://en.wikipedia.org/wiki/Scheme_%28programming_language%29)
instead of Nix's purely functional language. GuixSD is much younger and supports
fewer packages.  Furthermore, since it's part of the GNU project, you can expect
that it would be very partial toward free software.
{'fraction_non_alphanumeric': 0.05891856958207669, 'fraction_numerical': 0.006839724256785868, 'mean_word_length': 4.391695702671313, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 32, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5417930', 'n_tokens_mistral': 5151, 'n_tokens_neox': 4837, 'n_words': 2668}