NixOS vs Guix - A non-programmer's novice perspective

Good day Crafters,

As everyone knows, Guix is derived from NixOS, but what keeps people from jumping ship from Guix to NixOS? Lets go over the pros and cons of each!

Guix:
Pros

Libre software collection - can view and modify every program.
Emacs emphasis - Most of the Guix people I see use Emacs, so if you like Emacs, Guix is definitely for you
Guile - Guile is cool, but I don’t know much about it other than that’s what Guix is written in. But by that same token, Guix has a uniformity about it in regards to it’s Guile usage, so it is easy to write things for the system and to integrate other packages using Guile into it.
Shepherd - Also written in Guile, the service manager. If you are opposed to the total domination of systemd in Linux, Shephard is a good one to try out. Or even if you’re ambivalent regarding systemd, giving Shephard a try should on your list. If you’re positiviely into systemd, like say, for writing service scripts for NixOS or $Distro, I could see adjusting to Shepherd could be difficult at first. Furthermore, Shepherd hasn’t been ported to any other system, unlike say… OpenRC with Alpine and Gentoo and others, or runit with Void and whatnot.
Rolling system: With “guix pull” and “sudo guix system reconfigure $CONFIGFILE” it is easy to keep your system up to date. With NixOS flakes, there are myriads of ways to do so, but usually I do the following commands - “nix flake update” → “sudo su” → “nixos-rebuild boot --flake flake.nix”, then reboot into the new system with presumably a newer kernel and programs. I’ve tried other rolling systems as well, but forgot the commands to upgrade them, lol. In any case, what I am trying to say is that it is virtually effortless to keep Guix up to date!
System control: Both NixOS and Guix are for power users, but Guix goes one step further with the uniformity of Guile in the system as mentioned above.

In conclusion regarding the pros of Guix, I would like to state that they’re numerous and that Guix has a very slow evolutionary process compared to the likes of NixOS and other rolling systems. But this slow evolutionary process could be compared to the likes of FreeBSD or Debian, and I imagine that if you’re not looking for the latest and greatest all the time, it could work for you.

Now for the cons.

Cons:
Outdated packages - Yup, other than the kernel it seems, most of the packages found in the standard Guix repo are a bit behind compared to NixOS unstable/rolling or even regular stable. So if you need features of $PACKAGE(s) then you might be waiting a while in Guix.
Guix pull/reconfigure takes forever - Yeah, system upgrades can indeed take a while! Grab a cup of tea or coffee or something while you wait. Not always a bad thing, but a bit annoying for us who want a upgraded system here and now lol.
NonGuix and kernel compilation - Same as the above really, if you use NonGuix, be prepared for your system to compile the kernel on first pull/reconfigure. So… yeah.
Prevalence of all things GNOME/GTK - I don’t really care for GNOME myself, I would prefer to use Plasma or Cinnamon. MATE is fine for what it is but still feels “non-modern”. This is a very subjective thing so I won’t count it as a real con though.
Guix development on mailing lists and IRC - I don’t have a problem with either of these as development platforms, but I can see how it might turn off people. Still better than Discord at least, lol.
Bordeaux and CI Guix substitute servers are sometimes down/slow - Infrastructure problems, I totally get it. I hope they get a huge grant sometime to pay for like a thousand servers.
Guix as a server host OS option - Not really under their control, just wish Guix was available at lots of places for hosting! So not really a con either, just an observation. Not like NixOS has a lot of places either, though.

I’d say those are the cons of using Guix, but some of those can be easily remedied! With Guix, for newer packages, you can use Nix if you want or Flatpak. In regards to Window Managers, they have been integrating Plasma into base recently, so yeah.

Now for NixOS pros and cons.
Pros:
Updated packages - if you follow rolling on NixOS, you usually have the absolute newest packages easily.
ZFS/bcachefs support: Guix might actually have this, I don’t know…
No kernel compilation unless you want to: Self-explanatory, but really same for Guix unless you use NonGuix, unless there’s a way to get substitute non-libre kernels lol.
Bigger community: Pro and con really…I don’t think I would have to go much into this one, we have a nice big community here! Y’all are the best!
More available options for services: Kinda a big deal for me anyway… like I can get wordpress and an ircd very easily in NixOS. With Guix I’d have to go to Docker for all that…

Now for the cons:
Cons:
Bigger community - A bigger community can also lead to bigger disenfranchisement of certain community members sometimes, their voices might be heard. This isn’t a good thing.
Documentation is all the place: Yup. Finding good docs for NixOS involves lots of searching and trial and error…
Things break here and there: If you’re on a rolling flake like I am, some programs you need can break every now and again, not a good look. Whereas with Guix, since it evolves a lot slower, less chance of stuff breaking…
Everything is always up in the air: By that I mean that there’s a lot of feeling of “chaos” in NixOS, that things constantly change in regards how NixOS should be governed, how it should be used, who should use it etc. Guix has a more defined purpose.

So those are my thoughts on NixOS vs Guix. I believe Guix is the better choice overall despite using NixOS(Mostly for gaming). Take the pitchforks down, I’m only here for polite discussion! I think in the future I will probably switch all my machines to Guix, what are y’alls thoughts on all this?

6 Likes

This is an aside, but I didn’t knew that. So I went for a short walk into the 140,000 commit history of Guix and had a look at its first commit:

diff --git a/guix.scm b/guix.scm
new file mode 100644
index 0000000..2e5c008
--- /dev/null
+++ b/guix.scm
@@ -0,0 +1,525 @@
+;;; Guix --- Nix package management from Guile.         -*- coding: utf-8 -*-

TIL

2 Likes

Outdated packages - Yup, other than the kernel it seems, most of the packages found in the standard Guix repo are a bit behind compared to NixOS unstable/rolling or even regular stable. So if you need features of $PACKAGE(s) then you might be waiting a while in Guix

While the outdated part may be true at times, having to wait until an update lands (given you’re okay with crunching the numbers yourself and not relying on substitutes) in guix proper isn’t. Guix makes it relatively easy to work around outdated packages as it supports package transformations.

So let’s say you want the latest version of atop, you could say something like:

guix shell --with-latest=atop atop

and spawn a shell with it. You could even go as far and say that you want to build a package from a completely differen repository (maybe from a fork) and from a specific commit (or branch with --with-branch=pkg=branch ) like:

guix shell --with-git-url=atop=https://github.com/Atoptool/atop.git --with-commit=atop=e1d759de286e71dba62ba1a33cab401266614fc0 atop                       

if you want to build a package with a local patch, you could say --with-patch=my-unpatched-package=./my-cool.patch and so on. There’s a section in the manual on this: 10.1.2 Package Transformation Options.

There’s also the possibility of doing this kind of transformation in your config.scm or home-configuration.scm or in manifests using options->transformation:

(use-modules (guix transformations))
;; ...
(define latest-atop
  (options->transformation
   '((with-latest . "atop"))))
;; ...
(packages 
;; ...
  (latest-atop atop))

the advantage of this approach over, let’s say defining a package variant of atop and modifying the version numbering or the way how guix fetches the source is, that, if you always want the latest version of a package you don’t really have to manually keep book of updates.

Another cool thing, if you’ve written a guix shell command with package transformations you like and you want to have that as a manifest or as a part of your config, you could just say --export-manifest with it:

(optiplex (~)) λ guix shell --export-manifest --with-latest=git --without-tests=hello --with-latest=atop git atop hello
(use-modules (guix transformations))

(define transform1
  (options->transformation
    '((with-latest . "atop")
      (without-tests . "hello")
      (with-latest . "git"))))

(packages->manifest
  (list (transform1 (specification->package "git"))
        (transform1 (specification->package "atop"))
        (transform1 (specification->package "hello"))))

and generate somewhat usable and working scheme code containing the transformations you want to apply to packages.

if you use NonGuix, be prepared for your system to compile the kernel on first pull/reconfigure.
unless there’s a way to get substitute non-libre kernels

nonguix provides substitutes at https://substitutes.nonguix.org, you can use them during the first pull/reconfigure like:

guix system reconfigure /etc/config.scm --substitute-urls='https://ci.guix.gnu.org https://bordeaux.guix.gnu.org https://substitutes.nonguix.org'

there’s documentation in the nonguix repository (Nonguix / nonguix · GitLab) that describes how to permanently add the substitute servers to your system configuration in the section " Substitutes for nonguix". I should add, that the nonguix substitute servers may need some time to catch on after each iteration of updates to the kernel, so chances are, they may not be available if you pull shortly after a update series.

7 Likes

Thanks for the info! I never realized this stuff!

Glad you posted this. I use Guix System as a non-programmer, rather a hobbyist programmer, and learned a lot from the replies! A lot of stuff mentioned were things I never realized, despite daily use of Guix and trying to read through the guix manual constantly.

One thing I wish Guix had was more example driven documentation, such as the info posted by @theesm.

Thanks fellow crafters!

2 Likes

Where did you find documentation on options->transformations, does it need to specify a string “atop”? Seems like it uses specification->package?

I have my home.scm setup to use package symbols, just wondering how this works using package symbols and the use of specification->package

Either way, the code you have for latest-atop works, was using it to get the latest version of Nyxt, i.e. 3.11.8 , and. defined latest-nyxt :smile: and applied the same prescription for “atop”.

Appreciate the examples!

Where did you find documentation on options->transformations

Generally speaking the programming index (Programming Index (GNU Guix Reference Manual)) of guixes manual/info pages is always a good start to find these things. In case of options->transformation the docs are sparse and incomplete-ish, what was helpful for me instead, was reading the source code of transformations.scm (guix/guix/transformations.scm relative to a local guix checkout) to fill in the gaps of what the documentation lacks.

does it need to specify a string “atop”?

So the transformations themselves basically take a list of pairs:

(define (options->transformation opts)
  "Return a procedure that, when passed an object to build (package,
derivation, etc.), applies the transformations specified by OPTS and returns
the resulting objects.  OPTS must be a list of symbol/string pairs such as:

  ((with-branch . \"guile-gcrypt=master\")
   (without-tests . \"libgcrypt\"))

Each symbol names a transformation and the corresponding string is an argument
to that transformation."

with a transformation part, that can be any of:

(define %transformations
  ;; Transformations that can be applied to things to build.  The car is the
  ;; key used in the option alist, and the cdr is the transformation
  ;; procedure; it is called with two arguments: the store, and a list of
  ;; things to build.
  `((with-source . ,transform-package-source)
    (with-input  . ,transform-package-inputs)
    (with-graft  . ,transform-package-inputs/graft)
    (with-branch . ,transform-package-source-branch)
    (with-commit . ,transform-package-source-commit)
    (with-git-url . ,transform-package-source-git-url)
    (with-c-toolchain . ,transform-package-toolchain)
    (tune . ,transform-package-tuning)
    (with-debug-info . ,transform-package-with-debug-info)
    (without-tests . ,transform-package-tests)
    (with-configure-flag . ,transform-package-configure-flag)
    (with-patch  . ,transform-package-patches)
    (with-latest . ,transform-package-latest)
    (with-version . ,transform-package-version)))

and a string containing at least the package name to be modified and some other options (e.g. the branch name if you say with-branch and so on). I think the way the string is resolved to a package is similar to how specification->package does it (matching package by best effort).

1 Like

Thanks @theesm - super helpful!

for (define %transformations ...)
, what would be an example of how you would define the transformation-package-latest, i.e. as a procedure?