What's all the hype with Nix?

Hello, after a bit of looking around I’ve spotted countless blog articles (from otherwise trustworthy developers and ops) about how Nix is poorly designed, faulty and everything, and that people would be much better off sticking to (e.g.) Docker.

But still, I also see countless posts (here) about Haskellers using Nix to deploy their stuff. However, what I’ve never read is a clear comparison between Nix and other solutions, what are the advantages, drawbacks, etc. Since perfection is not of this world, surely there must be some drawbacks to Nix, right?

However, outside of the Haskell community, I’m yet to read a positive thing about Nix. Maybe they exist in communities that I don’t follow (say Ruby for instance) but I haven’t seen them.

So, what’s all the hype about Nix? Are most Haskellers using Nix because they’ve seen someone else use it as well, or is Nix adoption in Haskell the result of a carefully thought-through pros and cons weighing? And what’s the killer feature, besides (alleged) coolness and hype?

(edit: I realise this post might come across as provocative but far from it, I’m genuinely curious)

14 Likes

I feel like it is easier to use a specific set of packages together. I can just do nix-shell -p clang_7 llvm_7, I don’t know how to do that with docker (this might just be my lack of docker knowledge). And you can also install desktop applications with nix, which I think is not possible with docker. I do that for (versions of) packages that are not in Debian stable yet. I also feel like nix is more hands-off, I think docker always requires running a docker daemon in the background.

By the way, do you have links to some of those negative posts about nix?

1 Like

Thanks for sharing. I don’t have the links handy but will try to find them and will update the post.

Nix is multiple things:

  • an universal package manager: nix packages applications and libraries over multiple languages
  • nix allows you to pin these packages to specified versions, so you don’t break your project on a system upgrade
  • nix can provide a uniform development environment: it can make sure that your build tools for a project are the same for every developer (by pinning them and making them available in a nix-shell environment)
  • nix can generate your docker images for you

Docker only makes sure that the docker image on my pc is exactly the same as on your pc. Nix can do a lot more.

This with the downside that it has a steep learning curve, and it is untyped. Errors are often hard to understand and debug, certainly for beginners.

9 Likes

This is maybe vague and squishy, but to me, choosing nix vs. docker is like choosing purely typed programming like Haskell over, say, C++: After doing it a while, it is obviously the right thing, but it’s still kinda hard to convey that to C++ users. And, a bit like git, there is an elegant and clean core hidden underneath a, well, imperfect UI.

Maybe nix will be like Haskell: Used by a few with joy and for great effect, mostly ignored by the rest, and yet influencing the other systems over time.

26 Likes

I think there are at least two things at play here

  1. nix is a pure functional language and emphasizes declarativity so it’s natural I think, that it’s popular with Haskellers but I think that the more important explanation is that
  2. nix can do so much more than docker. (At least ergonomically.)

Both nix and docker give you the possibility to define reliable self-contained builds, which is probably the most important point in the context of Haskell, because cabal and stack wont install system dependencies for you. But with Nix you can additionally profit from

  • the ability to define your whole system declaratively
  • the ability to setup your developing environment declaratively
  • the ability to use Nix for all your declarative CI and testing needs
  • the ability to compose all your build definitions easily as first class citizens inside a programming language with the vast collection of build definitions others have collected in nixpkgs.

The great thing here is once you do one of these things with Nix you have a lot of synergy with doing also the rest. (e.g. packaging your own software with Nix makes it super easy to install on Nixos.)

Now I think theoretically docker could be used for all of that and I am quite foreign to docker so maybe it is even used for most or all of that. But I don‘t think it was made for or is used in all of these ways. And only if it could provide all those benefits we came back to 1. that the design of Nix is just better suited to use it in all of these ways.

Of course there is certainly the community capture effect that you are observing though. Haskell with Nix is in large part so widespread because a lot of people have invested a lot of work in making it as good as it is. From all I can tell they made the right choice though and I thoroughly enjoy being able to profit from all their work.

12 Likes

Nix is a time sink and a constantly moving target of ecosystem trends (now it’s haskell.nix). The documentation is extensive, but also incredibly inaccessible. You won’t make anything work without reading through countless blog posts, anonymous gists and asking on reddit, github or IRC, just to wait for a nix guru 1 month later to have discovered the impossible: a bug. And one you need a couple of years experience to spot.

If you’re up for all that, go ahead. For me, the benefits absolutely do not outweigh the cost.

10 Likes

Note that one could say the same to say, managing effects in Haskell.

Language support is still being explored and there are different takes. I do agree we have to do a better job at describing the differences.

I’m working on tutorials for all kinds of ways to get started with Nix at https://nix.dev/, but these things take time and effort.

19 Likes

Further discussion about this topic on reddit.

2 Likes

It took me a long time to warm up to Nix, but after six flawless major OS upgrades on my home and work laptops, which are always configured exactly the same way I might add, I’m completely convinced that Nix’s innovations represent the future.

So yes, it’s like Haskell for me: already good enough for production use, maybe never completely mainstream, but the epicenter of innovation for its domain.

10 Likes

a bit like git, there is an elegant and clean core hidden underneath a, well, imperfect UI.

Ah, this is reassuring to hear. I used to hate git, but as soon as I (accidentally) came to understand its (simple but inexplicably hidden) model (via git log --graph --decorate --all --oneline) I immediately started loving it and now I use it with great pleasure.

If Nix also has an elegant and clean core then I am much more likely to dig into to. I would welcome the thoughts of others.

2 Likes

It does! The two pieces are

  • There is a pure lazy untyped functional programming language. So, almost Haskell. The syntax is boring in some places, neat in others, and idiosyncratic in yet other corners. Like with any language.
  • Some values are special, namely “derivations”:
    • These values (I can’t say special type…) denote build instructions. Evaluating a nix expression to such a value is called instantiation.
    • These values can be realized. This executes the build instructions, and (if they don’t fail), produce an output path. These builds are hermetic, i.e. only stuff specified in the derivation can affect the output. Output paths are put in /nix/store, and are addressed by essentially the hash of the build instructions (not the output content).
    • Nix understands how derivations depends on storage paths, and how store paths depends on each other, so it builds what’s needed, can copy stuff including all referenced paths from caches.

That’s what I’d consider the elegant and clean core. All the rest (the sometimes obscure CLI, with old-style and new-style commands; nixpkgs with it’s concept of overlays based on recursive knots; stuff like haskell.nix) become manageable with that in mind.

9 Likes

I love nix and use NixOS, but I must also say that nix has bad documentation, bad errors, no typechecking, really lacking debugging capabilities (to my knowledge) and generally a disorganized community. Still it is the best build system to date. So I think the solution is to replace the nix language with something (dependently) typed. I think nix will evolve a lot though.
My experience using it for haskell was not very uplifting. Rust was better. I think it needs a sort of nix protocol which makes it easier to integrate with excisting build tools like cargo or cabal.

5 Likes

but I must also say that nix has bad documentation

There’s been quite some effort going into documentation lately, from RFC converting docbook to markdown to a bunch of tutorials being written.

We still have a lot of work to be done for sure and getting feedback what part of documentation is bad helps us prioritize what’s next.

bad errors

In Nix 2.4 (to be released soon) error reporting has been revamped thanks to all the donors and you can still donate and report errors to be improved.

no typechecking

That one probably deserves its own thread, but in short, most of the time evaluation error is still at build time, rather than at run time. So it’s not as bad as general purpose dynamic languages that fail at runtime. There is however research how we might have static types.

really lacking debugging capabilities (to my knowledge)

That’s something I’d love if we had a budget for! There’s a prototype that needs a lot of work. I’m hopeful as Nix gets more popular that eventually we’ll get resources to fix this.

generally a disorganized community.

Watch the news in the following weeks/months :slight_smile:

My experience using it for haskell was not very uplifting. Rust was better. I think it needs a sort of nix protocol which makes it easier to integrate with excisting build tools like cargo or cabal.

Did you try haskell.nix tutorial?

9 Likes

Does haskell.nix offer a lot of benefits over the default haskell-nix infrastructure? I’ve seen the name fly by a couple of times, but it seems that it isn’t as often used.

Yes. Official docs have some insight into it, although the main emphasis of that document should be that haskell.nix can map cabal plans or stack resolvers exactly into the same versions in Nix.

Default infrastructure ships with a flat list of packages, usually resolved from the latest LTS.

2 Likes

Last time I looked into using nix for some new project, I stopped at this point. It seemed like someone made a big workaround for some failing in nix that I didn’t understand. That kind of thing is immediately off-putting, since now my development setup would depend on both nix being maintained and understood, and some third party’s workaround being maintained and understood. Whose docs do I read when something goes wrong, who do I file issues with? I’m probably making it into a bigger problem than it is, but I’ve experienced enough of these situations that it makes me wary.

OTOH, I do use nix-based IHP because they’ve done all the work for me and I didn’t have to think at all, just run two commands. They’re also very good at making Upgrading documentation. For IHP, I mostly don’t even notice nix being there. But that doesn’t help my non-IHP projects.

5 Likes

I’ve had similar concerns, and ended up avoiding both Nix and haskell.nix for a while, and like yourself, I found the approach from IHP quite good, and almost seamless. I was also quite impressed with their deployment integration, all nix based, to their own “cloud provider”. That was for me the catalyst to dig further into it. I stumbled upon nixkell, and that was my starting point.

I must say, Nix is unnecessarily confusing, a lot of self-inflicted pain, especially by naming 3 things that are almost completely unrelated, Nix. Searching for solutions can be quite overwhelming, and easy to end up down the wrong rabbit hole. But once you get it working, it works really well. I think nix-shell, despite its ergonomics, is a game-changer for team work. The way Nix integrates with Docker can also be quite powerful, even if the documentation is sparse.

I ended up with the following setup (shameless plug), and it’s been working for me quite well. Starting new projects is easy, and ensuring that I can rebuild it and work on it regardless of machine setup (as long as it has Nix package manager installed), or that a coworker or someone else interested in a particular repository can do the same is very good.

That being said, I’m far from an expert on the subject, so take it with a grain of salt. :slight_smile:

3 Likes

Personally, I’ve had a difficult time getting into nix itself, but I am finding NixOS a real pleasure. Even as a beginner, in daily, practical, production use, NixOS is no more effort to maintain than Ubuntu. However, NixOS is more consistent and easier to ‘figure out’, so it gets easier as you go, whereas Ubuntu/etc are inconsistent and moving targets, requiring a consistent (or growing) amount of effort to understand and maintain. For a solid experience, you’ll sometimes need to contribute to nixpkgs, but that’s easy and a great way to learn more about nix and get that experience. If you are interested in nix, and not interested in figuring it all out ASAP, I would recommend starting with NixOS as a way to “ease” into nix.

That all said, despite being a bit mysterious and similar to haskell in mentorship requirements, nix still seems (IMHO) to be best-in-class when it comes to a modern packaging solution that needs to encompass all aspects of building and managing project dependencies. If your project is not simple in that regard (dependencies), using nix to build your project is probably worth the expense.

9 Likes

Let’s say you want to update some tool to a newer version in you project. You need to make sure everyone updates their version of the tool on their machine as well. With nix you just update the tool version in shell.nix and when your colleagues pull it down they will now also use the new version. Same goes for if you have multiple projects, it you want to try something out, just try it out for that project, you don’t need to worry about whether or not it’s compatible with the tools in the other project. I’ve seen it reduce the friction with experimenting and testing new things.

6 Likes