Files
blog.norg/posts/nix.norg
2026-03-23 21:54:55 +00:00

168 lines
13 KiB
Plaintext

@document.meta
title: Why Nixos is the Coolest Operating System
description: I really like Nix
authors: [
Adumh00man
]
categories: [
linux
blog
nix
]
created: 2026-03-22T19:35:56+00:00
updated: 2026-03-22T19:43:25+0100
draft: true
layout: post
version: 1.1.1
@end
* The Nixos Philosophy
Nix is the all in one solution to every problem you could have with Linux. It prides itself on being a fully declarative way to install
and manage system packages, and It (mostly) achieves those goals. Before trying to involve oneself in such matters, though, an important
distinction to make is that Nix as a concept, and a package manager, is seperate from Nixos as a system. Nix can, and should, in some
cases, exist outside of Nixos. But, let's get onto that later.
** Origins
If you wanted a full rundown on how nix came about, then you're in the wrong place. Go read wikipedia or something. The main thing that
you need to know is that the nix language, and therefore the packaging system, was made on a whim for a university dissertation. First
of all, that's pretty insane. Making an entire programming language for the sake of it, and I wouldn't even be surprised if he didn't
get full credit. It quickly caught the attention of all the linux nerds out there, and before long it had evolved into the nix project
that we know and love today.
** Reasoning and Methodology
The main draw of nix as a concept is it's reproducability. It works similarly, and often in tandem with, Git. The git working tree is a
simple concept. A long ledger of changes (more commonly called diffs), that when put together results in a full codebase. Nix uses this
principle to its advantage, and I will demonstrate this by comparing nixpkgs with another common package repo, the AUR.
*** The AUR
The AUR is the Arch User Repository, a gigantic collection of packages uploaded by anyone that can be asked to figure out how PKGBUILDS
work. PKGBUILDS are a form of makefile, that is used as a standard way of declaring dependancies, versions wherein, and how to build
a given app. These PKGBUILDS are stored within the repos they are associated with, and are therefore versioned alongside the app.
When you upload an app to the AUR, and it is approved, a static version of your app, ie one commit, is hosted on the aur domain. This
url is read only, and cannot be viewed like something hosted on github. To install the app, you clone the repo and use `makepkg -si` to
compile.
The key part of all of that is that only one commit is hosted at a time. Because arch is a "rolling release" distro, they
see no need to waste storage on older versions of apps. This is an issue, when there is a breaking change and you cannot roll back
to an older version of a package, because it no longer exists. This is remedied slightly by the pacman cache, but that only goes for
your local machine. If you need a specific version of an app, then either compile from source or give up.
But, I hear you ask, what happened to git versioning? Can't you just roll back to an older commit and use the PKGBUILD from there?
This, my friend, is where Nix comes in.
*** Nixpkgs
Nixpkgs is, without exxageration, a git repository. Every time you install a package, the entire repo is pulled to your local machine.
Despite the fact that, at the time of writing, it has over 200,000 packages, it is still small enough, because of how diffs work, to
be downloaded every time you need to update an app. The reason for this is that it leverages git histories to their maximum potential.
Git, as I said, is just a long ledger of changes. All diffs are stored in the .git folder, along with some other stuff that might be
important to someone someday. Every time you make a commit, a new hash is generated. It isn't important how the hash is generated,
just that every commit has a unique hash associated with it. This gives rise to revisions. With this hash, you can address a specific
state of the ecode at that commit, and this is what nix uses to stay so small.
Every package has a .nix file, that details its build process. This can be as simple as compiling one file to a binary, all the
way up to compiling the whole linux kernel. Nix in of itself is a wrapper for every other build system, which means that any app
that can be built can be run on nix. Hence, when enough apps are compiled, nixpkgs becomes completely self sufficient. For an app
to be built with nix, all of its dependancies, and the builder itself, must also be built with nix. This means that, instead of using
a manner of different build systems, and rolling release nonsense, that means that you can never be sure if you're getting the same
version of a dependancy an app was developed with, you simply call another nix file, at a specific rev, or commit.
This leads to what is known as a dependancy chain. Because you call every dependancy with a specific rev, you can make sure that you
are getting the right version. When you get down to the actual source code, that isn't nix, you download the specified rev of the third
party repo, and compile that. If an app compiles once, it will always compile, because the git ledger should never be changed manually.
** In practice
Due to the existence of flakes, something that I'll get to later, this is made much easier. No more "it works on my machine", because,
for all intents and purposes, all machines are identical when running nix. There are no outside dependancies, so there is no way
for an app to fail to compile. Nix as a package manager can be used on other systems, being monolithically configured with one file,
that can be shared and rebuilt on any other machine with (almost) exactly the same functionality.
Hang on, this sounds awfully familiar. Like a problem that system integrators have been trying to solve for years, but could only come
so close. And so, the quest for a system built with Nix began.
** Nixos, the coolest operating system
Nixos is what came of that endeavour. A system fully defined by code. A system that could be rebuilt over and over, with exactly the
same result, on multiple machines. This had the added benefit of the same git methodology that nixpkgs was based on. No more updates
that rendered your computer unusable! You could simply revert back to a previous revision of your system, using the same diff structure
that git uses, but with boot entries and packages instead of just code.
Nixos is the pinnacle of stability. By definition, there can't be a more stable system. By virtue of the fact that It can be rolled back,
it cannot be defeated in that regard. It is impossible to have conflicting packages, because, in theory, all packages can be installed
alongside eachother. If you want to install 50 different versions of the linux kernel at once, then go ahead! If you want to run 10
different versions of firefox on the same machine, there's nothing stopping you! You get all of the benefits of rolling release, while
also having the option of installing a 5 year old version of onlyoffice in the same breath.
And the best part? Your system config, in of itself, can be controlled by git! It's git all the way down! I can instantly have the same
system I did 6 months ago if I wanted to, the only difference being the user files, of course. Ah, the user files.
** Home Manager: An attempt was made
Home manager is the logical extension of Nixos. A way to control dotfiles, or really any file, through nix. Revisions, versioning, etc.
It seems like a good idea on paper, until you try to use it.
First of all, the way that home manager works is exactly the same as the nix store. It creates a load of read only folders, and then
generates the immutable config files within. Seems reasonable, why would you want to change them in the first place? Two words: Lock
File. Nvim is the main culprit when it comes to issues like this. The Lazy.lock file can't update, because presumably the entire
`.config/nvim` folder was created by home-manager, meaning that updating packages is nearly impossible. All home manager leads to is a
massive headache at the end of the day. Especially when you come across some unsupported app, where you have to paste in the non-nix
config so that home-manager can copy and paste it into a read only file somewhere else in your home directory.
Because of these issues, I have taken a different approach, which I will now go on a tangent about.
** The Better way to manage dotfiles
Stow is an old GNU utility. It calls itself a "symlink farm", which is fancy speak for "it takes files in a directory and links them to
another place". The idea is that you have a folder with all of your dotfiles in, the ones that you actually care about, and stow links
them to your actual .config directory. I used this for a while, in order to manage my hyprland and nvim configs more nicely.
Due to the fact it's a GNU utility, however, it's really old. And doesn't have nice features. It was never intended to be a dotfiles
manager, so didn't have the killer feature that I would need to make a proper nix config. Multiple host support.
I have 2 machines that I have nix on. My laptop and my desktop. I want a similar experience between the two, but some things I want to be
different. Nixos thought of this, and made it so that you could have different outputs in a flake, that represented different systems.
But what about all my other nonsense? My monitor names are different between the two machines, and I had different keyboard styles, so
wanted different modifiers too! This could be remedied by loads of scripts, but that was boring. I needed something new. Something...
Intuitive.
** Doot: The Fast, Intuitive dotfiles manager
[Doot]{https://github.com/pol-rivero/doot} is my choice for a dotfiles manager. It's fast(ish), configurable, and, most importantly,
was built with multiple hosts in mind. If you want to see how it works more closeley, click the link at the start of this paragraph,
or have a look at my [Dotfiles]{https://git.voidarc.co.uk/voidarc/config}, which I think are pretty cool. For those of you that can't be
asked to have a look, though, I'll explain the concept as simply as I can be bothered.
Your doot repo is located in the `.dotfiles` directory, next to .config. When you run `doot install`, the folders in your repo are mapped
to your home directory in the same structure as they were in the repo. Eg, if you put a .zshrc in the root of the repo, it will end up
in the right place. So far, this is exactly the same as stow, the only difference being where stow would link a whole folder, doot
creates the structure in place and only symlinks files.
Doot can be configured in the doot folder, in the root of the repo, that will not be mapped to the home directory. The doot config
contains things like exclude files (like .gitignores and licences), the diff viewer you want to use to see file changes, and your
different hosts. Doot manages hosts intelligently, using the hostname of the machine as an indicator. Here is my host config:
@code toml
[hosts]
"HACKSTATION" = "pc-files"
"mobile02" = "laptop-files"
@end
The keys on the right correspond to the different hostnames, and the keys on the right correspond to the folders that contain the
dotfiles specific to that machine. These folders are located in the root of the repo, and within them, contain another structure
that is relative to your home directory. Eg, in the pc-files directory, there is also a `.config` directory, with some specific hyprland
configs that only work on my PC.
** What was I talking about again?
You could, of course, version every single file on your disk using this method, but that sounds like a waste of time. There will never
be a world where 100% of a system is always generated by nix, because there will always be some random app that only compiles to an
appimage and uses proprietary config locations or something. Nevermind how you would manage something like a download folder.
I believe that Nix, and Nixpkgs, is the gold standard when it comes to software development. There are genuine, real world uses for stuff
like this. Sites like replit are fully managed and distributed using nix, because of how stupidly stable it is. You can define whole
Kubernetes clusters on nix, and then update them in place with 0 downtime. Pretty impressive. However, as tends to happen with nerds
on the internet (me included), the concept and utility that comes along with something like nix is buried under who can make the lightest
or best looking config.
** Moral of the story (or something)
Nix isn't for everyone. If you don't care about versioning everything in your entire life, then you're probably better off sticking with
something like arch. If you don't mind that you have slightly different configs across different machines, then there's no need for you
to learn how to use flakes so that you can make sure that you have identical packages on all of your systems.
But, It sure is fun to mess around with. If you're on the fence about trying nix, then this is your indicator to switch. It will make
you feel a great deal of things, but regret will not be one of those feelings.