Nix is hard in the way that programming is hard. Not everyone gets over the activation energy to be successful. The ones that do don't regret the effort. Nix is complex because the problems it solves are high complexity problems that other systems don't solve. Docker is not a substitute for Nix.
The solution isn't to use a weaker tool, because the weaker tool doesn't solve your problem. It's not uncommon to see a programmer use a spreadsheet, but you wouldn't expect to see a programmer use a spreadsheet where a database is needed. And you don't see people trying to use garbage-collected languages to write operating systems, even though they are easier to use than C. It's perhaps inefficient when a tool is too powerful for what you need, but it's a fatal flaw if the tool you use is too weak for what you need.
Nix let's you control your dependencies in a way no other tool even attempts. I can pin and patch any combination of dependencies, even conflicting ones in single environment, with reproducible builds— I'm in control of every detail. I would never consider a downgrade from that, but I'm open to upgrades if something even more capable came along.
Yes and no. Fundamentally, I agree with you. Nix is hard because it solves an inherently complex problem. But it's also hard because it has some usability flaws.
For example, I recently wrote a bunch of Nix and got an error that boiled to me forgetting to add a "name" to a derivation. That is absolutely my bad. However, Nix didn't tell me which file this derivation was in (it said 'unknown file' iirc), the stack trace also wasn't any help . And so I went hunting through the hundreds of lines of Nix I just added to find where I might be missing a "name".
Should I have tested my code incrementely? Absolutely, yes! But Nix should also be able to tell me which file I am missing the attribute in.
I say all of this as a huge Nix advocate and fan. It's wonderful, it solves so many problems I previously had and I intend to keep using it, but it's far from perfect.
I'm rooting for Nickel, I really am, but I am doubtful. Nix is so incredibly dynamic that I believe it's nearly impossible to give it a practical static type system. I say practicaly because I do believe it is possible to come up with a reasonable type system, it's just that it would be so complicated to use that hardly anyone actually would outside of extremely specific applications (see Agda, Idris, ...).
In order to get something more reasonable, I think we would also need to rethink both the NixOS module and nixpkgs DSLs. Which is of course possible, but such a momentous task that I don't see it gaining much traction.
I think it's more realistic, and maybe even sufficient to integrate better error reporting into Nix itself. This is surely also no easy feat, but I am confident some improvements could be made: for example, more acurate tracking of source locations.
And while I almost always prefer static over dynamic typing, writing a specific NixOS config feels like it's one of the moments where it's less important, because I don't care about all possible executions working, I just need my specific config to work. This all changes once you write your own modules, where you obviously want all configurations to work, but that is less important for end user adoption IMO.
Man i can't wait for Nickel to work with Nix. Feels impossibly difficult though.
I often think that making Nix logic + configuration is just a mistake. I kinda feel like i'd prefer something that output a JSON-like config, and that config was a deterministic instruction for my stuff.
I know why that sounds impossible or big or difficult or etc. but as a user, i often am writing something that walks and talks almost and so damn close to JSON. Most of it looks like simple configuration. But can i print a damn JSON object? Hell no. Because there's lazy function calls all over the place.
They managed to make something (and other similar langs) that looks like clean readable configuration, but acts like some obtuse bespoke logic where you can't know what anything is without running it - and running it to see output is weirdly difficult.
I am on Nix, but i kinda think there's more than one fatal flaw. I adore what they've done, but there has to be something better and more enjoyable as a system configuration.. i hope.
It's probably a tooling problem. I get that. But still.. i just want to see some configuration output. Why is that so hard?
I had thought the Nix 'language' was just a way to describe packages, dependencies and configs, more a config format than a language. Why would it need static typing?
Yeah in many ways, Nix is a research project that escaped the lab. It’s the first tool of its kind that also happened to become successful. You have to write in this dynamically typed Haskell with poor affordances for being a build system and fragmented ways of addressing pinning.
PNPM (a package manager for JavaScript/NPM ecosystem) does this with much better usability:
> let's you control your dependencies in a way no other tool even attempts. I can pin and patch any combination of dependencies, even conflicting ones in single environment
It does so with much lower user facing complexity than Nix. I like flakes because they’re trying to follow a similar model, but still quite hard to teach newcomers:
- The CLI should literally have the same verbs as PNPM, but needs a bunch of complicated flags to do the same actions.
- The nix expression language is intimidating and has kinda bad tooling out of the box. I would love to use Starlark/Python/Typescript instead. Even Guix’s scheme language is more appealing to me, although Guix is too niche and GNU focused to be practical.
- Nix package files evaluate down to configuration for the Nix package manager, but I haven’t ever seen a good explanation for the basic essentials underneath all the abstraction. Every guide I’ve learned from and all the package defs I’ve read seem to cargo cult many layers of mysterious config composing config. Without easy to learn essentials it’s difficult to grok the system as a whole.
I would love to adopt Nix for developer tooling for Notion’s engineers, but today it’s about infinity times easier to work around the limitations mentioned of Docker+Ubuntu+NPM than to work around the limitations of Nix.
I looked at the docs, and it seems promising but I’d like to do something like: `garn add --dev git@2.3` and have git added at the given version as a dev tool. With config-as-code, is it possible?
I don't think you can ever get Nix as simple as PNPM, simply because native libraries are sometimes annoying, need to be configured at build time to a greater degree and because the problem space it attacks is so much larger than PNPM, which only deals with the JS/Node.js ecosystem.
However, I do think that there exist reasonable levels of abstraction that sacrifice some expressive power for simplicity and such systems could maybe expose a PNPM-like CLI. One example that comes to mind is devenv.nix [1]. While it doesn't yet have a CLI, its configuration file is YAML and relatively simple. I think there's more to be done in this space and I hope for tools that are easier to grasp in the future.
> Nix package files evaluate down to configuration for the Nix package manager, but I haven’t ever seen a good explanation for the basic essentials underneath all the abstraction. Every guide I’ve learned from and all the package defs I’ve read seem to cargo cult many layers of mysterious config composing config. Without easy to learn essentials it’s difficult to grok the system as a whole.
To me it sounds like the essential that you're referring to is the 'derivation' primitive, which is almost always hidden behind the mkDerivation abstraction from nixpkgs. This [2] blog post is an exploration of what exactly that means.
I'd also love for the documentation situation to be much better, in particular in terms of official, curated resources. But I'm not convinced that you actually need to know the difference between derivation and mkDerivation to make effective use of Nix, because in practice you would always use the latter. That said, mkDerivation and the whole of nixpkgs is essentially a huge DSL (I believe this is what you meant when you said 'config composing config') that you do need to know and is woefully underdocumented.
> I would love to adopt Nix for developer tooling for Notion’s engineers, but today it’s about infinity times easier to work around the limitations mentioned of Docker+Ubuntu+NPM than to work around the limitations of Nix.
One approach I have taken to is to specify the environment in Nix, but then generate Docker devcontainers from it, so most people don't come into contact with Nix if they don't want to.
I recognize this argument, but eventually it just becomes a wall of difficulty for people. I see the same problem with Gradle and Bazel. There's just something to be said about the work required to abstract fundamentally complex concepts into a simple and grokkable API that these systems just don't manage to get right.
People generally want to program to accomplish goals, and they want to minimize the amount of setup time and yak-shaving needed to start working on those goals.
Nix does solve a lot of complex problems and gives you a lot of control over your dependencies. But if the complexity to start using Nix for your project is too high, then you're going to opt for a less powerful solution that lets you get stuff done.
I say this as someone who really loves Nix and the power it provides -- the UX is a huge challenge for adoption. It's better to confront that fact if we want Nix to succeed.
The solution isn't to use a weaker tool, because the weaker tool doesn't solve your problem. It's not uncommon to see a programmer use a spreadsheet, but you wouldn't expect to see a programmer use a spreadsheet where a database is needed. And you don't see people trying to use garbage-collected languages to write operating systems, even though they are easier to use than C. It's perhaps inefficient when a tool is too powerful for what you need, but it's a fatal flaw if the tool you use is too weak for what you need.
Nix let's you control your dependencies in a way no other tool even attempts. I can pin and patch any combination of dependencies, even conflicting ones in single environment, with reproducible builds— I'm in control of every detail. I would never consider a downgrade from that, but I'm open to upgrades if something even more capable came along.