Let me give an example: let's say you want to use xmonad on top of Plasma. NixOS doesn't have any simple way to configure that. You have the mutually exclusive options for one or the other, basically.
I know Nix is powerful enough to do this, if I wanted to go offroad and create custom packages/derivations, but that's the point where I am no longer happy with the utility/work tradeoff. It's what ultimately sent me packing back over to arch.
When I came back to arch, I was left hankering for NixOS's declarative package management, if that could be somehow reconciled with the baseline arch package system. This led me to using the aconfmgr utility, which checks in packages and system configuration files into a home-based filetree.
Once you've got it set up, aconfmgr can regenerate your current configuration from scratch, declaratively! I was able to check the aconfmgr tree into my dotfiles repo, so now it tracks my home state AND my system state. Unlike Nix, this still uses file-based configuration, but it's all versioned and fully reproducible, so I no longer particularly care about that caveat.
I was pleasantly surprised to find the contrary to be true: in my experience, NixOS is the only distro to give you _every_ DE+WM combination pre-generated as a login session that you can pick from the display manager.
I think it's fantastic that we have a declarative, deterministic, idempotent package manager that works across all these OSs. I've used it happily for years now without ever bothering to try NixOS.
I get what you're saying, but the reality is the opposite. Nix is _far_ more powerful and flexible than anything you can do in Arch. It sounds to me like you just wanted a particular packages available, and Nix didn't have that. But if you have the inclination to learn Nix, you will be able to customize your system, in a safe and repeatable, declarative approach, far more than you could ever do with Arch.
With that being said, I would use NixOS over arch + aconfmgr 10 out of 10 times in a production DevOps environment. What time/effort you give up in terms of instant usability is immediately recovered when you start working in terms of modular and widespread system deployment.
It's been a long time since I last used XMonad, but wouldn't the following configuration suffice?
services.xserver = {
enable = true;
displayManager.sddm.enable = true;
desktopManager.plasma5.enable = true;
windowManager.xmonad.enable = true;
};
Even if there isn't an official NixOS option to configure things the way you want, you can always put whatever configuration you like with the "environment.etc" option. For example, the following configuration would create a file in /etc/example/example.conf with the line "name=value". environment.etc."example/example.conf" = ''
name=value
'';I gave up on XMonad + Gnome before I switched from Ubuntu to NixOS 6-7 years ago. Does XMonad + KDE work? I would love to get such combos working in NixOS / home-manager.
(We also need to bite the bullet and get X-less Wayland working properly. I think I might be tempted to plan everything out at once so we don't get conflicting refactors or too much complexity.)
You wouldn't give access to memory raw without any safeguards. (Typical package managers can just arbitrarily dump files or remove files)
It takes a structured approach. Laying over a graph database on top of your filesystem which is read-only typically.
This helps provide guarantees and also every application has its own hermetic sealed dependency closure.
Nix is truly revolutionary and it's getting steady adoption. Give it a read if you don't know about it. You can adopt it on any Linux distro without using the full NixOS.
I write a lot about it on my blog.
A little not exhaustive list of features that Nix provides:
- Not only an 'app installer'. It is a fully feature functional build system where reproducible builds are guaranteed (This is unique with GUIX up to my knowledge) on any linux distribution. Safe-reliable distributed builds are also possible.
- Fine grain de-duplication of dependencies (libraries, frameworks) to save disk space
- Safe, unprivileged installation of binaries in a multi-user environment on a single machine.
- Atomic upgrade and rollback
- Allow multiple variations of the same package with different options & versions installed in parallel without any risk of conflict
- Solves definitively all ABI breaks problem you encounter on traditional package manager, even with shared library.
1. Nix is not a "package manager" and I think it's better at first to not think of it as one because you'll assume how it works incorrectly. It is a package manager, but it doesn't have the same workflow as yarn or etc. That trips a lot of people up.
2. You need to read the Nix Pills documentation. It is not long and guides you through every abstraction so you understand from the basics how it works. Nix is actually pretty self descriptive. I setup my home's Linux Router entirely by just hacking and searching through the nixpkgs repo without understanding things, but if I'd read the Nix Pills things would have been so much clearer to me. Especially when debugging or reading through what a derivation was doing.
The configuration system very easy to understand and work with. I think this is actually the perfect distro for a "one off" home server because configuration management is built in so it is easy to rebuild my server from the backup of a single file.
It's much easier than most manually-configured installs (e.g. gentoo) though, because pretty much everything other than partitioning the disks has a default, so you need to make fewer decisions at install time.
Despite this, I think it's totally worth going through the pain of learning Nix to use NixOS. There is nothing else like it. I imagine other OS's will try to copy and borrow the ideas, in fact they are already doing this (see all the half baked immutable OS stuff out there...), but nothing is as good as NixOS at the moment.
Note: A notable exception is GNU Guix, which is another excellent OS/package manager that is very similar to Nix, with the far more approachable Guile (scheme based). Unfortunately the ecosystem is just not large enough to be usable for practical purposes - also it's hampered by the usual aversion to non-free software.
One problem is dynamically linked binaries, where the library points to a global position (like /usr/lib). In NixOS, different builds can depend on different versions of the same binary, so there is no single global location. This is not necessarily a bad thing in itself. And normal cases can be fixed with the patchelf [^1] utility. I couldn't make it work with a Z3 binary, so I finally gave up.
The other problem is when I tried to configure jackdbus. There's only one example [^2] configuration. It is marked as outdated by the wiki, and indeed none of the settings work for me.
Then I realized these two are not problems that Nix tries to solve. Pointing to a global binary is okay for some quick fixes. And JACK module is better to work out-of-the-box, I don't want to dive into all of the configurations before I haven't even used it.
Now I use Ubuntu for casual desktop applications and write Nix derivations for projects that need reproducibility. And I think I find my perfect balance.
[^1]: https://github.com/NixOS/patchelf [^2]: https://nixos.wiki/wiki/JACK
But overall: it makes me more productive. It is my secret weapon to manage the complexity of software development.
There is Terraform and Ansible, of course, but Nix seems like it could combine the strengths of both of them.
Or would it be better to install NixOS? Could I then choose not to use systemd? Would that be hard?
Is the idea that you can define your system in a file and reproduce it more or less automatically?
How does this compare to Guix?
Yes. (And you won't need to use systemd with just Nix and Nixpkgs)
> Do I then just stop using the native package manager?
No
> Is the idea that you can define your system in a file and reproduce it more or less automatically?
Yes
> How does this compare to Guix?
Very similar. Guix is a fork -> rewrite, with more Scheme and more FSF policy. But core concepts have not diverged.
It's so much nicer than doing it ad-hoc.
The idea of Nix is that you can specify a package's dependencies very explicitly, and have it build in a hermetic, and reproducible, environment. It can handle all sorts of dependencies, be they same-language libraries, binaries, or native system libraries. You can think of it sort of like firing up a docker container in which to run your build--if it works once, it'll always work, and if it works here it should work everywhere.
NixOS adds to that by essentially making the running system one of the packages managed by Nix. You specify what packages should be installed, how those packages should be configured, what services should be run, users that should exist, etc. When you build, the operating system you're running on is replaced with the new one. If anything breaks, you can trivially roll back. If you build the same config on a different host, you'll end up with the same system (albeit with slightly different package versions).
Guix is basically a fork of Nix (or started that way); it's got a very similar approach to Nix (and GuixSD to NixOS). It uses Gnu Shepherd instead of systemd, and uses Scheme for system config instead of a custom language.
Using a special command (nix-shell) whenever I needed to do development things (e.g. Rust builds) was not my idea of fun.
Some other things, like overriding GDM's monitors.xml file, were pretty much impossible to do.
Maybe it's better if you just use it as a base for servers / containers.
Funny you should mention that, because that's exactly what got me using Nix everywhere :). I've always hated installing tools and libraries globally—what if I need a different version for a future project?—so I like tools that sandbox as much as possible like virtualenv, cargo, cabal... etc. But these tools are all language-specific and have their own limitations (especially around native libraries and dependencies written in other languages).
nix-shell gives me the equivalent of virtualenv that works for everything. I can have a single sandboxed environment even if my project uses a bunch of different languages and I can manage everything in a reproducible, low-overhead fashion. No more worrying about making a mess by installing tools or packages globally.
Then, once I got really used to that, I spent some time setting up direnv[1] and lorri[2]—both of which are themselves managed with Nix, of course!—so that my environment gets automatically configured as soon as I enter a project directory without needing to call nix-shell explicitly. To be honest, the experience is still a bit rough, but it works well enough day-to-day that I have my reproducible sandbox cake and eat it in an mostly frictionless way too :).
[1]: https://direnv.net/
Quite the contrary. Nix makes it easy to override contents of files, even those that are part of a package. Some things to look for are: "mkForce" for NixOS modules; "override", "overrideAttrs", "symlinkJoin", and "meta.priority" for Nix packages.
I use Nix on macOS, wishing I could replace all my brew usage with it. Working on a home-manager derived setup.
The dev workflow mentioned by tikhonj https://christine.website/blog/how-i-start-nix-2020-03-08 (including a "derivation" building a container from the example project).
I wrote a blog post about doing this with python, but it's straightforward to generalise.
As far as I understand it, it's basically Alpine Linux with the Nix package manager and tools preinstalled, but it worked pretty well for me.
Knowing the difference of tools in the belt is like knowing the blades themselves. You can always make your own tools.
If I can't package something with nix, then I call it "metal"
https://hn.algolia.com/?dateRange=all&page=0&prefix=true&que...
The current thread seems pretty good so far, though, so we'll leave it.
Just like proglangs got destructuring and lambdas gradually.. maybe OSes are influenced by nix.
After I gave up on the idea of preserving an existing Linux install (that used a file system, namely, btrfs, that NixOS's installer does not currently handle), and just allowed NixOS's installer to nuke my block device (i.e., my "hard drive"), it was easy for me to set up and configure my NixOS install to my liking -- and I know very little about Nix and NixOS although I consider it worth learning, which probably greatly affected my attitude, which has historically had a large effect on whether I succeed or fail at sys-admin-y tasks.
Where the learning curve gets very steep is when I tried to build something from source code! I would've liked to have built Emacs 24.4 from source, because that is the version against which my Emacs Lisp code is tested, but I gave up. (I'm using Emacs 26 instead and spending time adapting my Lisp code -- something I probably never would've needed to do if I could've built 24.4 because I am moving off of Emacs.)
If you're using x86_64, there are tens of thousands of packages with pre-built binary packages, so it might be you never have to build something from source to get the desktop environment you want.
Sometimes it shines ex:
I messed up my x11 config as well as drivers and just booted into the previous generation like it was no big deal
I needed to install a version of electrum that was only available on a specific git commit. I just specified the commit and booted into a shell with it
Sometimes it sucks:
Learning to package arrive 3rd party software can sometimes be really complicated and it might be the only way forward.
Lots of steam doesn't work out of the box compared to Ubuntu.
Make sure you're using Proton 5.0 until this [0] is fixed.
But starting off with a new computer, copying over a config file from one of your existing files, building...and ending up with _exactly the same system_, including all those tweaks to _this_ file and _that_ config, and the cronjobs you've set up over time, and all your different rc files, is magical.
Most of the issues I ran into were just nix being different from other distros I use, so I did have to relearn a few things.
The remainder of the issues are the sorts of things one runs into with a non-rolling release distro. For example, a program I use got a feature I want last September. I'm going to have to wait until March for it to hit stable, since NixOS is on a September/March biannual release schedule.
The good news is that I am running the latest version of that package just fine now; Nix lets you install "overlays" of the package system into your home directory (or globally), and I just copied the package definition into the overlay, updated the URL and SHA256 sum to point to the new version and it "just worked."
Downside of course is when I upgrade to NixOS 21.03 (the march release), I'll have to remember to remove my overlay version of the package, or I'll be frozen on that version. There may be some fancy way to work around this which I haven't discovered, but since I have like 1 or 2 packages in that state at any time, I just manually do it when I upgrade.
Then anouther half day to get comfortable with home-manager to configure my user settings
If you're willing, its worth the effort
Generally you don't specify a specific version as a dependency unless it's necessary, but when 'building' the system, specific versions are used. If things break during an upgrade you can roll back to the previous version. Keeping those older builds around will mean keeping older versions of the packages used in those builds (libcurl, for example). Periodically, you can purge older generations (i.e. builds) and collect garbage, which will clear out packages that aren't used anymore. It would be very strange to end up in a situation where you had dozens of instances of libcurl _being used simultaneously_ (though I guess that would be possible if lots of packages had very special requirements, and ended up building libcurl with different flags or something).
There may be circumstances where you have a _specific_ version dependency, and you can specify that too. That would mean having multiple copies of the same package, even in a single generation. Obviously this usually means major versions, so you don't usually see _dozens_ of them. Having specific dependencies on minor versions would be a major code smell IMHO.
Anecdotally, my NixOS systems (both desktops and servers) can grow up to, say, ~50 gb of system files in a few months, at which point I'll clear out older generations and GC, which gets them down closer to a typical Linux distro size. Once or twice, I've seen a system balloon up over 100G when I was doing a lot of experimenting with packages.
Oh, and incidentally, most of the different versions are only visible to the packages that depend on them. Your 'default' environment is one such package, and only sees one of each of it's dependencies. It's not like you have dozens of instances of packages crowding /lib or anything (since /lib doesn't exist in the first place). You have to go looking in the Nix package store to find the actual files.
- Traditional distro: you cannot end up with that
- Flatpack, snap etc.: you cannot avoid that
Nixpkgs doesn't wontonly package multiple versions of libraries. But as you upgrade you will accumulate old builds of libraries until you GC. The meaningful question is not how many of X do you have installed, but whether you have multiple versions of X reachable from GC roots.
The old libcurl will still exist on your system to allow you to rollback to previous states of your system, but you can always run nix-collect-garbage if you want to free up disk space.
This is similar to the situation in Arch Linux where pacman keeps all downloaded packages, and you have to run paccache if you want to free space.
- libcurl is 615,616 bytes
- curl itself is another 192,480 bytes
Not counting man pages.