How to Learn Nix
ianthehenry.com
ianthehenry.com
I wanted to point something out that the series doesn't do a good job of highlighting:
You can use Nix alongside your existing package manager.
They won't conflict. You can set up dev environments with Nix without drinking the kool-aid. I still have Homebrew installed, and I still occasionally reach for it in the rare cases where Nix is missing some package I want to try. But I am sad every time I do: I never really realized how unbelievably slow Homebrew is until I tried Nix.
So if you're Nix-curious, you can try it out without committing to anything upfront. I didn't make the switch until part 19:
https://ianthehenry.com/posts/how-to-learn-nix/switching-fro...
Nix is weird and hard to learn, but it's a lot like git in that respect. Yes, the UI is terrible. You have to learn the difference between `reset --hard` and `reset --mixed` and it's weird and unintuitive but you eventually get over it.
And people are using it despite how unintuitive it is, because of how valuable it is to them. No one is arguing that `nix-env -qaP package` is a reasonable command to ask a fellow human being to type, but people are willing to type it anyway because the benefits are worth it. As a fun example, a few weeks ago I wrote up a little hack that I would not have even attempted before spending the time to learn Nix:
https://ianthehenry.com/posts/janet-game/how-to-patch-emacs/
> So even if something bothers you about the software you use every day – even if you find a bug in tmux, or wish that you had some additional jq function or whatever – you probably aren’t going to do anything about it. It’s not worth it; it’s too hard.
> I am obviously projecting here: that is the way that I thought before I started using Nix. I never would have tried to change this Emacs behavior back then.
> But now?
> Now I can get a working build environment for any package I want, just by running nix-shell. I can write a patch, and I can ask Nix to automatically apply that patch to the latest version of the package. I don’t have to worry about maintaining my own fork or manually updating it – I can keep using all the same commands to list and upgrade and uninstall packages, regardless of what I’ve done to them.
I think this is what all the old greybeards have always been getting at when they talk about software freedom, this blurring of the line between user and contributor that is possible with F/OSS. I know for a fact that there are some HN posters who do use apt-get and related tools this way (that Debian developer who taught his kids to use Xmonad, for example). But I do think it's something Nix is especially good at, as a flexible, source-based package manager.
It's really nice to be able to treat your customized builds in a first-class way with a mature system for managing software.
Btw, if your main use case for this is customizing F/OSS, there's a SaaS offering you can use for free to recover binary caching without even having to set up a build server. Pretty cool if you have multiple computers! https://www.cachix.org/
* I don't want to learn nix, nor do I want to learn apt, brew, pip, npm, crates etc. beyond a handful basic commands: install, remove, list all, list package (version & deps), update (at version). A one page cheatsheet would be fantastic.
* There is a ton of QA work sunk in standard package manager workflows. Is there a way to leverage this work? You allude it is possible, hopefully there is a one page cheatsheet explaining how.
Regarding obscure command syntax, I use bash aliases to give names to the most common 7 git commands (which constitute 99% of my daily usage) and never have to remember any git command flags.
npm is a great example of why: pretend that all you have is `npm install -g`. That's sort of how a traditional package manager, like Homebrew, works. But that's not typically how you use Nix, just like you don't typically globally install npm packages. Instead, you write package.json files -- which isn't very hard, because you already know JSON.
But in order to write the Nix equivalent, you have to learn the Nix expression language. You can just copy a template shell.nix file and modify it slightly (as you might for a package.json file), but it's likely that that will be frustrating, because... well, because you still have to learn about garbage collection, and channels, and lots of other incidental things that don't map as cleanly to traditional package managers.
There are cheat sheets, though. I linked my Homebrew <-> Nix translation guide above, and the NixOS wiki has one for apt-get:
https://nixos.wiki/wiki/Cheatsheet
But this requires so many asterisks as to be not extremely useful. For example, that page lists `nix-env -u` as an equivalent of `apt-get upgrade`, but it's not. `nix-env -u` is hopelessly broken and will not do what you want. There actually isn't a "right" way to upgrade packages if you're using nix-env. It's just not a thing that Nix can do.
Which sounds crazy at first glance, but remember: nix-env is like `npm -g`. Even though that's a first class concept in most package managers, it's sort of bolted onto the side of Nix, and accepting "the Nix way" of doing things is important to have a pleasant relationship with the tool.
Even with a package.json you will often use `npm install <package_name> --save`.
You don't go chasing a git commit hash on a third party site to do that
Language-specific package managers like NPM or Cargo or Composer are not designed for a universe in which packages inhabit a monorepo where compatibility is ensured simply by coordination of changes in that repo. They're built on top of a different kind of infrastructure.
They also face different challenges since their focus is much narrower, i.e., libraries in a single language with a single build system, rather than whole applications whose build system can freely change in a fairly open-ended way from version to version.
It would be pretty cool for Nix to have some version constraint solving built in, and for Nixpkgs to host more versions of many packages. There's precedent for that in a way that wouldn't require radical change to Nix and Nixpkgs in other source-based package managers like NetBSD Pkgsrc and Gentoo Portage. It would also be cool to provide some built-in machinery for pulling package recipes out of old versions of Nixpkgs (or searching a global registry of some other kind for them). Whether the latter happens will probably depend on the future of the flakes implementation, and extending it backwards will take manual work. There's already sort of a proof of concept, though, in the implementation of one tool for generating Python packages for use with Nix (mach-nix).
So in conclusion, Nix is awesome to use if you invest time to learn the Nix expression language. Otherwise you have to stuck with the default packages provided by nixpkgs.
You can't translate Linux knowledge to a NixOS config directly, you need NixOS' documentation to understand the "NixOS Way" of doing things, and the NixOS way of doing things does not translate into other distros. And the documentation is difficult to understand and at times seemingly arbitrary.
You have to commit to learning NixOS and understand that you are only learning NixOS, it won't help you use anything else. Other Linux distros help you learn Linux in general and inform your understanding of Linux system construction, but NixOS is its own thing. Plenty of people learn NixOS anyway, and more power to them, but it's definitely pushed me away.
If one weren't using NixOS to do it, it would be done with your own templates and configuration management, and probably without the huge advantage of being able to rebuild a whole immutable system without leftovers from prior configurations.
those who do, say that it's a great idea, but implementation is a bit hacky and not well documented
NixOS came out in 2003. For context, that's when Xen came out.
LXC came out in 2008; KVM (Linux's built-in VM support) came out in 2007; Docker came out in 2014.
Nix and NixOS aren't containers (or VMs, etc.).
> If it were a legitimate abstraction layer, then wouldn't it have caused fewer problems in implementation? And wouldn't it have seemed more intuitive to Unix experts? Yes... Reinventing the wheel again.
The basic concept of Nix is (a) use the `--prefix` argument of ./configure scripts to keep things apart, and (b) use the `PATH` end var to choose what we want to run.
In comparison, containers are much more recent, require more invasive changes (i.e. support from the kernel), etc.
Personally, I like using containers to run binaries. Putting a whole Linux/Busybox installation inside one seems to defeat the point though...
Having said that, I'm moving towards NixOS for reasons detailed in another comment.
[0] It's ugly but it works. I'd love to find a lightweight curses-based data structure editor.
I personally dislike both projects though, when it comes personal desktops. Silverblue is heavily influenced by Flatpak and I don't expect RPMs for GUI applications to survive in Fedora. NixOS needs you to learn Nix which is a pretty steep learning curve and like you said, that knowledge probably won't translate anywhere else. You're probably better off investing your time learning things like shell/python scripting, Ansible, and Docker/podman.
This is also why Nix and NixOS painted itself in a corner; the presented value is only relevant if you are hacking away at it. When you have a smooth GUI experience it really no longer matters what the technical goodness underneath is.
Users shouldn’t have to care what their GUI uses underneath, but it could be the difference between building your own pseudo-declarative layer (which you now have to maintain in perpetuity and handle all the small edge cases), or getting something that is already declarative as the backend and simply generating a config file from the GUI (https://github.com/nix-gui/nix-gui).
EDIT: Also composition. Users could, if they wanted to, augment the GUI generated configuration using the built-in Nix features for composition with config files, which is a lot easier than trying to do the same with traditional system managers.
As a User I want to select an application to run so that I can use the application.
This applies to practically everything, if you want to play a game, you don't want to dick around with installers, managers, layers, configurations etc. Just point and click, that's all it should need.
I also do think certain users will care about e.g. extensibility/composabilty, as soon as they have to do anything outside of the officially blessed path. Having the ability to compose things nicely is pretty useful. It’s the difference between having to recreate the entire GUI configuration manually and just being able to dip into the config for the (likely small) non-standard part of the system.
As good (or as bad) as the technical underpinnings can be, as long as the user gets what they want most of the time they are fine with it.
Nix is one big advantage of course and that is that is isn't a commercial endeavour beholden to markets and income. So it doesn't really matter what general users might want or think (at least not at this stage). We also still have the same problem that is always present and that is content availability. If a user wants to install a Netflix client but none is available, it doesn't matter how good the tools are. Even the best UX can't help when the desired content isn't available.
There is such a project already: https://github.com/nix-gui/nix-gui
Once it doesn't depend on (yet again) a daemon, registry, and other system-level components but is understood by the shell (or DE) instead, you get a user experience that something like Nix cannot deliver (or at least, not without cutting down on the whole "learn this language to then learn those features to then get work down" thing).
I dislike Flatpak because it encourages package maintainer obsolescence. I heard a guy from OpenSUSE saying in a MicroOS presentation that why create, manage, and use RPMs when we can just use Flatpak. I also don't want to touch Flatpak anymore because people from GNOME are involved in it.
It's a shame to hear that kind of talk coming from the openSUSE world when Zypper did so much to raise the bar for high-level Linux distro package management tools. :(
openSUSE does an awesome job getting a hell of a lot of mileage out of RPM, from the vendor-based repo management to BTRFS snapshots to the huge and powerful (cross-distro!) automated build service.
Yeah, I don't think it'll last in the foreseeable future judging by how these distros are jumping on the Flatpak/Snap bandwagon. For these distros, package management might as well be dead.
I expect a few distros, such as Alpine Linux and Arch Linux, to remain relatively free from the influence of Flatpak and that's what I'll continue to use on my personal machines.
The "package manager" paradigm doesn't fit Nix that well, which is why it's a painful experience when you come to it from the angle that it's another Linux distro.
(IMO it makes more sense to think of Nix as "declarative Docker that doesn't need Linux namespaces".)
To be fair, when it gets installed on a personal, non-developer desktop machine, Docker typically is just another package manager.
It's absolutely true that you're missing out if all you do is use `nix profile install` like you might use `apt-get install`, though.
The projects do rely heavily on Nix for infrastructure stuff, and I have to explain it to unprepared developers often.
The best angle is to explain it as "like Python venvs, except works for any combination of programming languages". That sets for correct expectation for feature set and complexity.
P.S. The single biggest huge blocker is lack of support for nix-shell in VSCode and JetBrains IDEs. Every other complaint is a minor trifle in comparison.
For the VSCode case, does the Nix Environment Selector extension not do what you want? https://marketplace.visualstudio.com/items?itemName=arrteria...
> No, not really. [...] [E]xplaining it as "like Python venvs, except works for any combination of programming languages" [...] sets for correct expectation for feature set and complexity.
That's definitely a good description of the development environment use case, for people who know what Python venvs are for. It's also accurate, as far as Nix is about Nix profiles. Nix profiles are like Python venvs.
But all or close to all of the packages in Nixpkgs work just fine even if you have no profile at all set up for them— they behave correctly even if you invoke them directly from their paths in /nix/store. If you look at the install target as `/nix/store` rather than `/nix/var/nix/profiles/...`, then `nix-build` is just a source-based package manager in the ordinary sense which:
• installs each package to a unique, content-addressed-ish prefix
• uses the Nix language and Bash like Homebrew uses Ruby, Portage uses Ebuilds + Bash, MacPorts uses Tcl, etc.
• happens to have a really good build caching story
And your tools that build Nix profiles (`nix-env`, `nix profile`, `nix-darwin` and `nixos-rebuild`) aren't doing package management in the sense of building or installing anything, but instead just build convenient facades (out of symlinks) for accessing all of those packages installed to /nix/store in a more convenient way. The venv-like properties of those facades (symlink forests) just emerge from the one-prefix-per-package strategy of the underlying package manager. (In the case of profile managers that manage services, they also run some activation scripts.)
All of that is not to say that what I outlined above would be a better strategy for describing Nix to developers who just want to take advantage of environments that their DevOps team has prepared for them. I think you've settled on a really good explanation, for the reason that you outline.
If you're the Nix guy at work, you probably already understand what I wrote in this post, and have good reasons for preferring to present Nix to the developers that you support in the way you do. What I want to point out is more for the benefit of others, especially people who've done packaging or sysadmin work with other distros but maybe don't get how Nix works, maybe because they're turned off by all the FP jargon.
The lesson is this: there is an old-fashioned, familiar sort of package manager underneath the tools Nix users interact with. The essence of how that package manager is different from what came before can be boiled down to a single sentence: each variation of every package gets installed to a unique prefix. Once you have that, you can do wonderful things like build in snapshot-free rollbacks; allow unprivileged, per-user installation of packages; or generate venv-like per-project environments; and all of the other cool things Nix enables. Nix's complexity and power both follow from that one tweak, from what it took to get there on the one hand (the concept of derivations and various properties of the Nix language) and what it buys you once you have it (polyglot, venv-like setups and lots of other goodies).
I think for many developers with Linux experience, probably getting a reasonable NixOS desktop setup is straightforward.
There are some compelling benefits to Nix/NixOS, but these also require getting past a steep cliff in the difficulty curve.
I took this as an excuse to try NixOS myself and an opportunity to provide anecdata.
Previous Linux experience: Lots, including about 7 years of Gentoo use, some Arch and the usual distro hopping before that. Mostly on laptops (not counting VMs). Lately it's mostly been the BSDs so I'm a little lost.
It took me about 45 minutes from searching for their site to have a working XFCE install using their minimal install ISO with VirtualBox. Certainly a different experience, but with their install guide and searching "nixos xfce" you'll get it done.
Promptly rebooted and went for an encrypted ZFS root - less straightforward but after a few PEBKAC snags I got it up in an hour or two.
My immediate impression is that this is great but not being allowed to just
# which zsh >> /etc/shells
rubbed me the wrong way. Definitely something I'll consider using in the future, seems like a good fit for i.e. a VPS you might want to move easily.Naturally I haven't learned the config language fully, but it seems easy enough if the docs aren't terrible.
> My immediate impression is that this is great but not being allowed to just `# which zsh >> /etc/shells` rubbed me the wrong way.
Yep. That kind of thing will come up; on NixOS, root's interactive whim doesn't own /etc— `nixos-rebuild` owns /etc. But of course, both root and nixos-rebuild are you, so that's not so bad. :)
For those curious (I assume the parent poster already figured it out) the NixOS way of enabling ZSH as a login shell is the following one liner:
programs.zsh.enable = true;
which will both ensure that it is installed and on the PATH, and add it to /etc/shells for you.As a rule of thumb, it's generally a good idea to check the NixOS options to see if there's a module defined for configuring a program before just adding it to your `environment.systemPackages`. Here's NixOS' zsh configuration options, for example: https://search.nixos.org/options?channel=21.05&from=0&size=5...
(`programs.zsh.{shell,prompt,loginShell,interactiveShell}Init` are your escape hatches; you can put whatever custom zsh scripting you want in there)
You can use NixOS to learn more about Linux quite well. You can't really ruin everything by mucking around at the low-level. Just rollback to previous generation. I've definitely learned a lot due to NixOS allowed me to hack with impunity.
So — for one thing — in my personal case, it helped me at one time when I was experimenting with kernel build flags. With the caveat that finding how to change them was (surprise surprise) typically non-trivial in Nix in the first place... so it may be a feeble counterpoint... but still, after I found how to do it, NixOS made rebuilding new OS with different kernel flags absolute breeze, with basically 0 worry if I bork something (I mean, except maybe going to deep hardware params hacking such that would risk fraying some electronics) — I'd always automatically be just one GRUB entry away from a previous working configuration. (Though also useful to have `git commit`ed the previous /etc/configuration.nix from before I made some risky change, so that I could easily go tweaking again from there.)
I see the benefit of declarative configuration as an admin at work where we need to set up many systems the same way. For home desktop use I don't really see the point, I don't think it's a tech that fits perfectly in every scenario. Like most technologies there's usecases where its benefits shine and the drawbacks are irrelevant, and others where it's the opposite.
For example I often come across software that isn't packaged for my OS and I like to just compile them and try them out without having to do the whole packaging routine.
edit: in particular, going just Nix (not NixOS) on work machine(s) allows me to fall back to apt-get/brew quickly when a particular tool is not (yet) on Nixpkgs.
Has there been a change in ZFS licensing? I thought it was always going to remain poorly integrated into the Linux ecosystem.
Kinda typical... nice to have though!
Interestingly, NixOS excels at ZFS integration.
Because NixOS builds everything from source with transparent binary caching, always upgrades your system as an integral while, and performs upgrades atomically, you'll probably not even notice that ZFS isn't in the mainline kernel as you use it. NixOS will never upgrade your kernel to one that's incompatible with whatever version of ZFS is in the repos, and it'll never leave you in a partially upgraded state where your new kernel is installed, but your new ZFS modules are not— even if you pull the power during an upgrade.
ZFS feels very native on NixOS. It's great
It remains a kludge rather than something that can really be thought of as an integrated Linux solution. Even if it works okay in some situations.
If what you want is just snapshotting and you want something that's in the mainline kernel, I guess there's BTRFS. Bcachefs seems to be coming along nicely, but who knows when it'll really be ready.
——
1: https://papers.freebsd.org/2019/BSDCan/jude-The_Future_of_Op...
Lucky that you don't need to run NixOS as your OS to get a lot of the advantages from it then. I use debian for my boring desktop applications but have Nix available to me for when I need any e.g. development tools.
"Just install this one package to get CUDA working"... no. If I do that, then in two months when I want to do something else I'll find my OS is no longer capable of being used that way. And in four, when I want this specific version of CUDA working again, I don't remember how. The instructions probably wouldn't work anymore anyway.
NixOS allows me to put in down in terms of code, and the code practically never stops working. It's also immortal -- I've never needed to reinstall it. If I did, it'd be painless, but that's only ever happened in case of hardware failure.
It's the best part of Nix.
This has been available on traditional Linux for quite some time with btrfs snapshots.
But the real problem is that software does not understand nix either.
For example loads of scripts expect /bin/bash to exist, but on NixOS it is missing. Want to run a random python script from github? Well that's a bummer, because there is no nix version of a random library this script uses. Also no-machine server and Chrome Remote Desktop don't work, and these are the two remote desktop solutions which work on spotty 4G.
And I had to ditch NixOS, because my employer forced me to use a proprietary VPN, and I there is no way it would run on NixOS.
system.activationScripts.binbash = ''
mkdir -m 0755 -p /bin
ln -sfn ${pkgs.bash}/bin/bash /bin/.bash.tmp
mv /bin/.bash.tmp /bin/bash # atomically replace /bin/bash
'';
For python, you're best off using a virtualenv anyways. For proprietary binaries, you can almost always get them to run using steam-run. But the nicer way is a wrapper script to set up LD_LIBRARY_PATH, or custom derivation to patch their ld lib paths.Yeah it requires some elbow grease sometimes, but what distribution doesn't? Maybe Fedora/Ubuntu? I think the pain really is all that prior Linux knowledge is non-transferable and you have to learn how to fix things in the Nix way.
I think it's important to manage expectations about Nix and that includes being realistic about what's easy and simple what isn't.
There is your problem, I don't want to spend time writing wrapper scripts, or researching how to craft my buildFHS for every little piece of software I will run once for an oddly specific purpose.
Running the proprietary VPN on Arch Linux was as simple as running debtap, and then installing the package via pacman, even though the package shipped by the vendor was made for Ubuntu. It even figured out the dependencies automatically.
I know I could do the same thing on NixOS, but it would be way more clunky and time consuming. For example: this is how a package is installed from a .deb using nix: https://github.com/NixOS/nixpkgs/blob/nixos-19.09/pkgs/tools...
If Arch can do it in two commands, so should NixOS, just with two lines of nix :)
In fact proprietary binaries will be much easier to run since you don't have to do with non-reproducible builds in some source repo/build system.
Have you considered reading the manual? NixOS is not for you if you don't want to spend time learning the basics.
I have run xilinx vivado inside FHS within 15mins. Mostly figuring what libraries are needed for all binaries.
https://nixos.org/manual/nixpkgs/stable/#sec-fhs-environment...
On Arch I just do `yay -S nomachine` and call it a day.
But I really believe that someday the NixOS community will catch up, but currently it is not for me, since sometimes I want to get stuff done and not tinker with my system.
> since sometimes I want to get stuff done and not tinker with my system.
Plenty of people do get their work done on NixOS, so good luck with that attitude.
As a NixOS user, I did learn a lot about what is part of Linux distributions and what is part of the kernel, and how they interact. Compared to my previous Ubuntu knowledge, of course. If I would have ran Arch, I would have learned similar things.
This is kind of true on a surface level, but NixOS experience can be super helpful for setting up other distros because it turns Nixpkgs into a repository of high quality examples and demos that are always up to date.
Once you learn some basics of reading Nix code and how the NixOS module system works, the Nixpkgs repo itself becomes an excellent cross-distro resource on how to configure Linux software, much like the Arch and Gentoo wikis. I often consult Nixpkgs on how to do things in Linux for the purposes of configuring another distro or helping another user to do so! :)
What made NixOS stick is running up against some problems where Debian itself was ill-suited and seeing Nix's power. For example, building an image for a Raspberry Pi can be done with a handful of config lines. Changing between a cross compile and an emulated compile is also a handful of lines. This kind of power feels akin to the general lisp / functional curse where certain things become so easy they aren't even well documented because once you understand the system it's second nature.
Another benefit - I've modified kernel source and I've written my own modules, but they always fell by the wayside due to the maintenance burden of a compiling a custom kernel package. With Debian, I would end up reading kernel source plenty of times to figure out what was going on, but it was effectively read only. Whereas with NixOS, adding kernel overlays is straightforward. Using what is essentially a source distribution plays to the larger philosophy of Free software.
I've started https://nix.dev about a year ago to provide a resource for newcomers.
I'm working on comprehensive language tutorial next, but I'm mostly interested what you'd like to learn when getting started.
Some more NixOS-specific stuff would be really nice, if it’s in scope. I think a lot of the power of NixOS comes from the composition aspect, but I haven’t managed to figure out how mkOverride, mkIf, mkDefault and everything else actually work (rather than at a superficial level). I’m not sure if something as simple as adding an item to an option list from 2 separate bits of config is possible for example.
Along the same line, another thing I’ve found hard to discover is patterns used in the standard library. For example, I recently learned about makeBinPath from some random Nix file, and I’d really like some way of discovering quality of life stuff like that without needing to randomly come across it in some Nix code.
- How to update an in package information that has no setting for it in the function signature
- How to setup the night-light feature in sway
1. how to install outside of NixOS, mostly to use home-manager, in a flake-y way using the new `nix profile` thing that supercedes nix-env. The few folks I've spoken to seem to prefer to use NixOS as a shell, then to manage their dotfiles with home-manager, and trying to figure out how to manage this global state in profiles with flakes (e.g. I've heard ~/.config/nixpkgs/flake.nix is the location, but hits on a web search for this file name are almost non-existent).
2. how does one _develop_ with flakes. I get confused about how to use the repl to add something into my config (thankfully there's :lf now!). Some simple walkthrough that goes from packaging a simple application and troubleshooting in the repl, using shell to check the build stages, etc, would be extremely useful. Once one gets over this hurdle, Nix becomes an extremely attractive tool to bundle existing code and manageg packages, and new users start to see the power of it.
It was frustrating reading all the official intro documentation on Nix and it only talking about nix-env (not declarative AFAIK) or how to use Nix for per-project dependencies.
Are there any resources on taking a production example of issues we face on a daily basis and solve it with Nix and explain in a way without someone has to actually learn all of Nix in the first place ?
Let me give you an example, I need three services running to be able to make changes to a package. The 3 services comes from the registry, so no docker files locally. As for docker-compose.yml it just starts the 3 services and builds the docker file for the package.
Now for the dev environment the way we are solving it is by creating a docker-compose.override.yml style. This works great isn't it ? The problem is we still need to support python2( I know, please don't judge). So we ended up with 2 dev environments one for each python version. So at the end I have two docker files for each version of python. 4 docker-compose files, one for dev and one for deployment. ( There are projects which reduced the docker-compose.yml files by adding the python-2 and 3 in the same file as different services but yes it blew up the file )
We might be overdoing this and completely wrong in the way we approached. I am open for feedback.
>> A store path Q is reachable from another store path P if Q is in the closure of the references relation.
>
> Good definition. Intuitive term.The latter being of course an instance of the former :) Your lambda uses a reference to a local variable `x`, so go follow it and transitively capture all its references, repeat until you've closed over all such transitions.
let a = // whatever
let b x = a + x;
let f x = x + b x; // closes over b and transitively over aI recently evaluated NixOS for a new server deployment. Being able to describe the entire state of the system in a single file is magical - it is so clearly The Right Way to do things. I am not a Functional Programmer but using the Nix language as just a config file is fairly straightforward. I left convinced that a simple functional language is the best way to make more complex config files, way better than Jinja2 templated YAML. (Though, functionistas, come down out of the ivory tower and make a language that looks C-family. Yeah, "it's just syntax" so why not make it easy for the proles like me to learn.)
However, I ended up giving up on NixOS for two reasons.
First, while learning the basics of Nix was easy I wasn't confident about the more complex things. Packages were missing features and I was going to have to start investing in reading and writing lots of Nix code. I couldn't continue ignoring the many intricacies of the Nix system if I wanted to be confident that I could quickly fix an issue at 2AM on a Saturday. As others have noted, there is a lack of good intermediate-level documentation apart from this great "How to Learn Nix" blog. My whole interest in Nix was being able to completely document the system so that future me or someone else could quickly understand how the system is configured. That doesn't work if you can't count on that person knowing Nix very well. Even if I invested in learning Nix it would feel like professional malpractice to dump some heavily customized Nix system on the next guy to come along.
Second, there's no LTS. That's fine if it's a dev machine, or if you have a professional full-time ops team watching package changelogs and testing upgrades. My machines need to survive with bare-minimum supervision.
It's been kind of a pain: Docker is easier to get started with. But the payoff seems higher because it does handle all these tools in a sensible way: For development I can switch between subprojects written in many different languages and get the exact Python, Java, etc. and all necessary libraries are in scope.
I've gotten it working on Linux, and I expect a little more work porting to Mac OS for teammates(mostly for things like switching from CUDA to CPU based on system), but using it should be similar to Linux. Mac doesn't support cgroups or Linux containers so sandboxing is weaker than Linux, so it's better to develop Nix projects on Linux and add other platforms afterward.
I would recommend it for polyglot or Python projects. But for single-language projects with a sensible dependency manager(Rust Cargo), there's not as much benefit.
I don't have time to play with it, but really hope that one day someone will write something that effectively "compiles to nix". As far as I can tell, that could be done using the Spack's python descriptions.
https://github.com/dhall-lang/dhall-haskell/tree/master/dhal...
https://www.haskellforall.com/2017/01/typed-nix-programming-...
Dhall is a generic config language with some programming capabilities (but not turing complete) that can compile to json, yaml, and other formats, like in this instance nix.
I want to actually declaratively say: here's an autotools package with some parameters I defined, give me the fancy overridable pure nix equivalent.
I barely write any C, but I've gotten very good at building C/C++ applications over the past couple of weeks by fixing broken derivations ahead of a release.
But, the use case is to reduce redundancy in the config file. Maybe when you have lots of configs, each with slightly different fields but the rest otherwise the same. Toml isn't really suitable for programmatically generating config like that.
For simple configuration, you can just leave 95% of the Nix language's power on the table and it feels really simple, like it's JSON or something.
You can work your way to to all the real features at your own pace.
But a couple of projects have come up lately that piqued my interest wrt syntax and alteratives (Since I am not sure about Scheme anymore than Nix (as a langauge) :-)
* https://github.com/maxmcd/bramble
* https://nickel-lang.org/This is true for far too many people for it to get anywhere, I suspect.
If you have hardware that requires non-free firmware you can use the "linux" package from the nonguix channel: https://github.com/nonguix/nonguix/
https://nix.dev/tutorials/ad-hoc-developer-environments#beyo...
This is less packaging related (more nix lang related) but here is my go to resource for functions: https://teu5us.github.io/nix-lib.html. teu5us extracted the builtin/lib function docs and put them on one place saving you from having it split up into multiple manuals.
One issue with nix is the content has been written down it’s very inaccessible. It is split up between blog posts, discourse, nixpkgs code comments, the wiki, Reddit, etc. When working on something in nix I’ll frequently have 10+ sources of information. The google-fu needed is strong.
My biggest recommendation is to dive into the nixpkgs repo and other public dotfiles as most likely what you are doing has been done.
I've struggled with this as I recently got a new Mac for work and I tried to set it up from scratch with Nix but I couldn't even get it to connect to the nixpkgs channel. I tried every solution I could find online for pulling the CAs and specifying the NIX_SSL_CERT_FILE, but it borked even after I left the office and connected through another network (and wiping and reinstalling Nix didn't seem to fix it, but I probably didn't do that correctly either...).
Eventually I gave up and went back to homebrew and setup scripts.
> If someone who contributes to Nix ever actually sees these blog posts, I hope that they take them for what they are: a weird kind of user acceptance test. Not demands or complaints, just the story of one person’s experience.
I thought Nix could be this; unfortunately it looks like it's an overengineered thing that requires that everything you do follows the Nix philosophy.
Linuxbrew had to compile everything from source, but Nix in a proot environment worked perfectly.
If you're not going to be writing packages yourself, whatever package manager you use, you don't really have to worry too much about The Nix Way for the use case you describe
Almost anything that achieves this will necessarily be as "overengineered" as Nix. What you're asking as it turns out is not a simple problem at all, and a "simple" approach to it will end up rather fragile.
I still don't understand why you need chroot and all other horrors. Just use RPATH to ensure you link to the right version of the dependencies, no magic or pseudo-containers needed.
It also means we can allow most build systems to "auto-discover" their dependencies rather than extensively coach them with explicit locations of everything (i.e. tens of configure --with-foo=... flags)
Do you find it works well for you?
I think that a lot of my pain points with Nix comes from not “doing things the Nix way”.
Made me laugh! :D
This material is gold by the way - I am learning NixOS and HomeManager myself, and a lot of questions I also have are addressed here. Thanks a lot!
But there is? First, by pinning nixpkgs you pin to whatever set of versions was within nixpkgs at the time. Then, if you want to change the version of a package, you can use overlays to poke at what source version is being used to build a package (or what flags it's being built with, etc). There's also nothing preventing your from mixing derivations from multiple nixpkgs pins within a single nixpkgs/nixos fixpoint for your system.
Stuff that in your shell.nix or /etc/nixos/configuration.nix or just nix-build it straight from a small .nix file.
Using an older Nixpkgs checkout might have a higher rate of success but if Nixpkgs never included the version you need in the first place that also doesn't work.
So the mechanisms you describe are in my experience very good in theory but often lacking in practice.
Then you could get the package from a fork of nixpkgs where it is present.
Yeah, but also keep in mind that uses the older version, plus older versions of all its transitive dependencies (from the same nixpkgs checkout). So, you could end up with multiple versions of glibc and other commonly-used libraries, but worse -- many known security vulnerabilities as well.
Another practical annoyance is that overriding attributes often does not work across a derivation. E.g. overriding the version attribute does not override the same version in the src attribute (which is used to download the sources) [1]. So, you may have to override the attribute in several places.
[1] Unless the derivation is defined in a non-canonical way: https://discourse.nixos.org/t/avoid-rec-expresions-in-nixpkg...
When the version matters, Nix has separate packages for separate versions. There are separate Nix packages for Python 2.7, 3.7, 3.8, 3.9 or 3.10, and there's OpenJDK 8, 11 and 17, etc.
You probably don't want to depend on an overly specific version anyway. If a security fix for one of your dependencies is released, you want it. Furthermore, CI ensures that everything within a channel is maximally consistent.
I think from my perspective it wil make more sense i.e. the first thing that OP runs into is:
“ nix-env -i git, right? Wrong. I mean, you could do that. But you actually want to say nix-env -iA nixpkgs.git. Why? Don’t worry about it.”
My Nix-noob but declarative mindset would assume the "A" is to add the install somewhere to a file needed to recreate the server at some point. Am I wrong? No idea… Actually, I already find it strand that you can call the package manager like that, shouldn't there be a declaration of the packages I want somewhere, should I not add the package that list (maybe a Yaml, like my docker-compose.yaml?) then ask Nix to make the installation consistent with the declaration?
The "-A" shortflag indicates that the argument given is an "attribute path".
Roughly: without the "-A", the command searches for packages named "git" and installs that. With the "-A", it will install the "git" package from nixpkgs.
home-manager is one popular way of declaring what packages should be installed. The nixpkgs manual explains a different way of declaratively managing packages: https://nixos.org/manual/nixpkgs/stable/#sec-declarative-pac...
Nix the standalone package manager offers some imperative ways of doing things, plus you can declare a package that depends on all your needs. Then there are a couple of optional declarative systems that you can use with standalone Nix which add extra functionality, like configuring services in a NixOS-like way or managing your dotfiles
Yes, I completely avoid 'nix-env' for that reason. It maintains a bunch of symlinks behind-the-scenes, but the 'nix-env' command itself is imperative.
If you use NixOS, the config option 'env.systemPackages' specifies which programs to install. This can be declared in the /etc/nixos/configuration.nix file. There are similar approaches when using Nix on non-NixOS systems (e.g. using the 'buildEnv' function from Nixpkgs to combine multiple programs into a single derivation/package, and install that)
Overall, I'm still on the fence about having to rewrite all the configuration files and documentation in Nix, but having a unified setup is enticing. Maybe there's a way documentation can we prevesred and translated automatically, but it seems difficult to me.
Next, I read about the concepts and tried to map them to Git in my mind.
In the end I had the impression that Nix is a cleaner, more general PyEnv.
Homebrew is very, very good at the things Nix is worst at.
But Nix is also excellent at the things Homebrew is worst at.
The new CLI that comes (disabled by default because it's still 'experimental') with the most recent major Nix release (2.4) goes a long way toward learning from the UX of tools like Homebrew. Hopefully changes like that will help more people get to the good parts before the UX warts turn them off.