Hacker News new | ask | show | jobs
by elt 1435 days ago
I have used Nix in the past and enjoyed it... for a while.

I will go against the grain and suggest not using it, especially for native projects of any kind (C, C++, Go, etc). In my case I was doing Go work, but the binaries that are built are usually alright, unless you require Cgo and libc gets linked dynamically (Go will do this without telling you). Suddenly that binary won't work on production! It broke my server and I had to force static compiling so Nix's libc wouldn't be linked dynamically.

This can happen in Go if you do something like look up the user's home directory or cache directory, etc. Suddenly your Go binary is dynamically linked...

2 comments

Nix handles native projects especially well. For the situation you're describing, Nix would automatically detect the libc dependency from the resulting Go binary. The only possible reason you could end up with a missing dependency in production is when you leave Nix out of the loop during build and/or deployment.

Nix's primary benefit is declarative and reproducible builds. But you can only benefit from it if you actually use it to build and deploy your projects. So instead of copying manually built binaries to production servers, you should create a Nix package and install that to your servers. Alternatively, you could use dockerTools.buildImage [1] to create a Docker image with all the runtime dependencies.

So my recommendation would be to actually use Nix, not avoid it.

[1]: https://github.com/NixOS/nixpkgs/blob/master/doc/builders/im...

I was referring to using Nix as a tool for my own development workflow. You are describing a much more integrated and involved use of Nix (Nix packages deployed to production, Docker, etc).

That only cements the idea of avoiding Nix if you're using it for your own development workflow and the entire team/production deploy isn't on board with it.

The real lesson here is "don't build production releases outside of a carefully controlled environment," not "don't use Nix." What led to the failure was the introduction of local dependencies to the production release. In your case, that dependency came from the Go toolchain that you happened to install using Nix. But uncontrolled dependencies could come from anywhere and the problem will persist as long as you don't take measures to control your build environment. This is where Nix really shines. It creates a controlled build environment. You can avoid Nix of course, but there's no avoiding the problem that Nix aims to solve.

> That only cements the idea of avoiding Nix if you're using it for your own development workflow and the entire team/production deploy isn't on board with it.

I disagree. Using it for your own development is fine as long as you keep it local. Either that or ship the complete dependency by building a Docker image as I mentioned earlier. Nix has various tools to make life easier even if it's only for personal development purposes.

We use it for OCaml because there’s nothing in OCaml that really exist to manage dependencies and build (opam and dune are awful). But it doesn’t work well with our Rust dependency. I think it could work well with our Rust dependencies (which needs to be packaged with a derivation and thus doesn’t work in a nix develop shell) if nix stops where Cargo begins, but it seems like it is not nix’s philosophy.
What do you miss from opam (dune is a build system - nothing to do with dependencies)?

Last time I checked it did pretty much everything you might need and was fairly pleasant to use.

To say that a build system has nothing to do with dependencies is pretty telling about the OCaml tooling mindset.From Maven to Cargo, almost every modern build system integrates dep management. Only C/C++ is still lagging in that regard.
It’s not lagging. How you install dep as conceptually nothing to do with how you link and build. You can tell dune to use dependencies installed with opam easily enough and opam takes care of managing and locking transitive dep. These are entirely different concerns. I am tempted to say "Kids these days" but that wouldn’t be condescending enough.
What is the actual gain of splitting dep management and build / link into separate tools? All I see is added complexity and ecosystem fragmentation.
as the other comment says, you can't have a build system that doesn't care about dependencies, otherwise different environments will use different dependencies to build.