Skip to main content

Command Palette

Search for a command to run...

From Arch Linux to NixOS: Diving into the Nix Ecosystem – Part 1

My first steps toward reproducible, declarative Linux systems

Updated
5 min read
From Arch Linux to NixOS: Diving into the Nix Ecosystem – Part 1

Nix is a concept known for its steep learning curve. It is hard to understand, harder to explain and nearly impossible to master - even for the nerdiest Linux enthusiasts.

In this post, I would like to share my journey of embracing Nix as a long-time Arch Linux user. Hopefully I can inspire a few people to get curious about Nix and even start using it.

This is Part 1 of the series, where I’ll cover how I got started and the background that led me here. Future posts will dive deeper into the technical side.

Where I come from

I was using Arch Linux as my daily driver for nearly 5 years. It was surprisingly stable and easy to use. The Ubuntu system I used before had more issues than the so-called “unstable” Arch Linux. I was using I3 window manager and Vim as my editor of choice. I used to update packages quite frequently. Arch Linux is usually the first to receive package updates. The AUR (Arch User Repository) had almost every package I needed. Arch wiki is great and any kind of issues were easy to fix with a bit of googling, thanks to a huge community of users.

However, there were a few quirks which annoyed me a little. I had to reinstall the OS a few times, due to a broken hard disk, migrating to a different laptop etc. Every time I reinstalled, it took me over a day to install and set everything up. I still ended up with a slightly different configuration. Each time I fix an issue (for example, getting Bluetooth to work), I end up forgetting how it was done and next time I had to research and figure it out again. I ended up documenting the list of packages I install, fixing common issues etc. But it became quite messy over time.

Declarative Programming

I was quite fascinated by the idea of declarative programming. From Wikipedia

Declarative programming is a non-imperative style of programming in which programs describe their desired results without explicitly listing commands or steps that must be performed

I was working heavily on Terraform at that moment. So the idea of declaratively configuring an entire OS sounded really interesting to me. To explain what a game-changing concept this is, here is a simple example of the difference between these two:

Imagine, you want to create a user in your system. In imperative style, it would be:

  1. Create new user - jayadeep

  2. Assign group for the user - net-admins

  3. Create home directory - /home/jayadeep

  4. Assign home directory permissions

You just instruct the system to do these in order. The system blindly accepts the instructions and executes it. In declarative style, it would be:

Make sure following user exists with the given configuration:

name: jayadeep
groups: [net-admins]
homeDir: '/home/jayadeep'

Then the corresponding program will run the logic to ensure that the system has the users created with the given attributes. Here is a more detailed explanation of the difference between these two.

In short, declarative syntax makes our life easier by hiding the implementation details.

Hearing about Nix, and getting started

Nix is a package manager, a build system, an operating system (NixOS), and much more. Before getting to the complexity of nix ecosystem, let me explain where I started. At first I heard about how nix can configure an entire OS declaratively. So I downloaded a NixOS ISO, booted into a VM and started tinkering with the configuration.

Here is a sample configuration of NixOS

{ config, pkgs, ... }:
{
  boot.loader.systemd-boot.enable = true;
  boot.loader.efi.canTouchEfiVariables = true;

  users.users.alice = {
    isNormalUser = true;
    extraGroups = [ "wheel" ]; # Enable ‘sudo’ for the user.
    initialPassword = "test";
  };

  environment.systemPackages = with pkgs; [
    cowsay
    lolcat
  ];

  system.stateVersion = "23.11";
}

Although the syntax is a bit weird (looks like JSON, but isn’t), the configuration is easy to read and understand. What it does is the following,

  • Enable systemd bootloader (alternative to grub)

  • Add a user named alice, with initial password test

  • Install cowsay and lolcat packages

With a bit of Googling, I came up with a basic configuration that I can install and boot with. I still didn’t have much clue about the inner workings of Nix though. Once the configuration is ready, I just had to run the following command and it immediately applies the changes

sudo nix-rebuild --switch

First working configuration

Here is my first commit on Git: Nixdots

This was my first working configuration after days of tinkering with config, restructuring, following various tutorials etc.

One clear advantage NixOs has compared to other OSes is that, the nix package ecosystem is really huge. It has over 80k+ packages available the repositories, which is much more than AUR or any other package managers out there. So I was confident that I would be able to configure the system to be able to completely switch from Arch Linux.

My first impressions

Declaring the list of packages like this was life changing for me. It allowed me to discard the messy notes. At every point of time, I know what packages are installed in the system by looking at this file. This made it really easy to reproduce the system in case of a reinstall.

Look how easy it is to enable Bluetooth in NixOS!

hardware = {
  bluetooth = {
    enable = true;
    settings = {
      General = {
        # Show battery percentage of bt headset
        Experimental = true;
      };
    };
  };
};

This small snippet did all the magic. Since NixOS forces us to manage everything declaratively, once we fix an issue and persist it in code, it is fixed forever! Every package and every configuration is versioned and hashed. Nix goes to great lengths to ensure that the configuration is highly reproducible, byte by byte, no matter where or when we apply the configuration.

Summary and Upcoming posts

You can find my current NixOS config on GitHub: https://github.com/kmjayadeep/nixdots. In the upcoming posts, I will explain more about Nix package manager, Flakes, Devshells and more.