Use NixOS-unstable
When starting with NixOS, I picked the stable channel, but soon realized that, for the applications I use daily, I’d rather have more up-to-date versions. So I created a complex setup where most things are from stable, and select apps are from unstable.
Some years later, I realized that a better approach for me is to just use NixOS-unstable. Unstable is a misnomer – it’s just a rolling, continuous release, which is gated by a test suite and is pretty stable in practice. What’s more, even if something break’s, its trivial to boot the previous generation. NixOS mitigates major drawbacks of a rolling release model, making it a reasonable
boring default to use on a desktop.
Don’t rollback; switch to a working config instead
Speaking of rollbacks, nixos-rebuild --rollback switch
is not the best way to do that. It rolls you back from a currently broken configuration, which requires you to boot the broken config and do some mental gimnastics to calculate how far to rollback.
Instead, boot into the configuration you want to rollback to, and issue
console /run/current-system/bin/switch-to-configuration boot
to make it default.
I’ve spent a lot of time looking for a good way to search for nix packages on the command line (eg, using nox
utility). But it looks like using NixOS Search is a better default (would love a cli frontend for that though).
Look for options before packages
Many larger things, like docker
or emacs
, have both a package and an option.
Most of the time, you want the option
, as it enables additional integration with the system (eg, starts systemd daemon or what not).
More generally, whatever you want to do with NixOS, start with looking for an option
, chances are the thing has first-class support in NixOS.
Don’t use nix-env
/ nix profile install
on NixOS
NixOS has two ways to install the packages. Declaring a package in configuration.nix
installs is “globally”, such that it is available to all users. Using nix-env
/ nix profile install
installs the package for the current user.
Originally, I used nix-env
to install most packages, and only gradually moved “important” ones to configuration.nix
. This seemed “reasonable”, but just made the state of the system less reproducible.
These days, I don’t use nix-env
at all. If I need a one-off utility, I use nix shell nixpkgs#ffmpeg
to temporary get it. For anything which I need more than a couple of times, I add it
to my system-wide configuration.
As an aside, this reasoning makes me hesitant to try home manager. HM manages user-specific packages, but for my single-user install I don’t want to have user-specific packages in the first
place.
Use buildFHSUserEnv
to run unmodified binaries on NixOS
NixOS has a problem with running random binaries from the internet, because it doesn’t have expected things like dynamic linker in a usual place. One way to solve this is to use patchelf
to modify the binaries. A different approach is to create a lightweight container around the binary, which sets up a “usual” environment. NixOS has a tool for that, buildFHSUserEnv
, but it might get tricky to use. Here’s how I set it up:
environment.systemPackages = [
(let base = pkgs.appimageTools.defaultFhsEnvArgs; in
pkgs.buildFHSUserEnv (base // {
name = "fhs";
targetPkgs = pkgs: (base.targetPkgs pkgs) ++ [pkgs.pkg-config];
profile = "export FHS=1";
runScript = "fish";
extraOutputsToInstall = ["dev"];
}))
…
]
And here’s how I use it
# Get random binary from the Internet
$ wget 'https://code.visualstudio.com/sha/download?build=stable&os=linux-x64' -O code.tar.gz
$ aunpack code.tar.gz && cd VSCode-linux-x64
# Running stuff directly fails
$ ./bin/code
./bin/code: line 62: ./bin/../code: cannot execute:
required file not found
# Activating FHS drops me in a shell which looks like a "normal" Linux
$ fhs
(fhs) $ ls /usr/bin
(fhs) $ ./bin/code
Some details on the buildFHSUserEnv
invocation.
- By default, it doesn’t include any packages.
Building your own env with X and whatnot would be chore. So, I base my FHS on appimage one, using
pkgs.appimageTools.defaultFhsEnvArgs
as a base
-
name
would end up being the name of the binary I use to drop into env
- In
targetPkgs
, I add my own packages.
-
profile
is just for me to be able to add (fhs)
to the shell prompt.
-
runScript
to run my shell, rather than bash
.
-
extraOutputsToInstall
, like pkg-config
, I
need to be able to compile stuff (dont’ remeber details at this point).