Hacker News new | ask | show | jobs
by flylikeabanana 965 days ago
Nix aims to solve a much more general problem than homebrew. If all you want is to get some packages on your system, there might not be that much in Nix compared to brew for you. The zen of Nix is that building packages is expressed as pure functions, where inputs, outputs, and side-effects are carefully managed. Thus, if you have specific build, packaging, or environment configuration to do, nix can be really helpful. Since everything is in code and every generated nix configuration is effectively isolated from the rest, it makes rolling back to previous configurations trivial in the event something goes wrong. That, and you can VC a config, and in general once a package is properly expressed in Nix it more or less solves the "works on my machine" problem
1 comments

I don't understand :(

Is nix like a npm lockfile then, carefully controlling specific versions of packages and dependencies on a per... what, per-machine?... basis?

Or is it kinda like a Docker container that can contain isolated programs?

Or something like pyenv or nvm that can let you switch between version sets?

A .nix file is a lot like a regular programming language, except the "compile target" is actually something like a big digraph of dependencies. Each package is hashed based on the content of the build steps and dependency inputs, so to nix "python 3.9" and "python 3.10" live in two entirely different places (because the hashes are different)

The next step is to actually take that digraph and instantiate a bunch of packages on your system. Each package has its dependencies symlinked to it using env magic, and bubbles up into your shell session or whatever.

All the different offerings in the nix ecosystem are based off this idea. Home-manager focuses on user session environments, NixOS extends the concept to a linux system (e.g. systemd units are managed in the same way - its just another hashed object in the nix store that gets symlinked to systemd), NixOps lets you do it to other machines, and nix-shell lets you create per-project development environments.

Nix flakes are the next evolution in the ecosystem, where some of the "inputs" get taken out of your env where they were black-box magic and put into a flake.nix (with a pinned version locked in flake.lock) so the input package set is controlled for across builds.

All good questions!

> Is nix like a npm lockfile then, carefully controlling specific versions of packages and dependencies on a per... what, per-machine?... basis?

Installation and management of software with Nix is generally handled via tools I'll call 'profile managers', e.g., nix-env, `nix profile`, home-manager, nixos-rebuild, darwin-rebuild (Nix-Darwin), Disnix, NixOps, etc.

These tools all support version pinning (typically via 'flakes', but alternatives can and do integrate this functionality with various Nix profile managers as well).

These profile managers collectively operate at the cluster, machine, and user levels, but on a given machine you can also manage arbitrary named profiles, and you can additionally use Nix without persisting any environment into which things are 'installed'. In the latter case, one can still use source control to pin those environments, allowing for general-purpose, polyglot, per-project package management.

> Or is it kinda like a Docker container that can contain isolated programs?

Yes, but the kind and level of isolation that Nix provides is thinner than Docker. It's most comparable to something like Python's virtualenv or Ruby's Bundler, where packages are installed natively on the local filesystem, but managed via environment variables and symlinks.

The only real difference there is that Nix packages are configured at build time so that they're very hard to find by the dynamic linker and so they're very bad at dynamically looking for each other, providing some additional 'isolation' in a weak sense.

> Or something like pyenv or nvm that can let you switch between version sets?

I wouldn't say so, but you could manage Nix profiles that way if you wanted to. The CLI would be clunky for this at best.

It's not just a lockfile, though the 'Nix flakes' feature does have a `flake.lock` file. It locks the revision of your 'inputs', i.e., repositories containing packages. The most common and important input is `nixpkgs`, which is kind of like the default package sources on a Linux system. It has glibc, bash, coreutils, etc. but also an extremely large number of other programs that have been packaged. And in a particular revision of nixpkgs, any package has exactly one version. So, yes, the versions of all packages can be locked.

As for the granularity: that really depends on how you want to go about it. If you manage a NixOS system (a Linux distribution built on Nix), you can control the versions on your system. But any project could have its own environment entirely. In fact, in any project you can have multiple versions of nixpkgs if you really wanted to.

It can be all of those, which is why its "better" than brew or some other package manager. At its core, its just a reproducible/hermetic way to declare and build artifacts.
Similar to npm lockfile, basically you can install an specific version of a program globally if you want, but it's not recommended, and you can have multiple configurations for different projects or folders with an specific version of tools/apps-
I updated a comment I wrote earlier about what nix is. Always remember to keep your mind and body pure (I kid, but purity is a common theme in nix).

Nix is a programming language plus utilities. It is designed for packaging software in a reproducible way (https://github.com/nixos/nix/).

Each package is called a "derivation", which is a function that takes inputs and makes output. The inputs are everything that is needed to make the output. It is "pure functional" package management - for the same input arguments, the same output will be produced. Nix is really fast because each derivation is hashed and cached and the language is lazy-evaluated.

Builds are "hermetic", meaning only the inputs specified in the derivation are available at build time. Contrast this to some packaging systems, where the build is done against some staging area where packages get installed as they are built and the output can depend on the non-deterministic order that packages are built.

Nixpkgs (https://github.com/nixos/nixpkgs/) is a large collection of recipes for existing software. It contains both rules to build software as well as "modules" to configure it or extend it. NixOS the linux distribution is also part of nixpkgs. There are lots of design patterns here and it can go pretty deep. There are also tons of hacks and patches and workarounds to make software conform to the way nix works. Nixpkgs also has a lot of useful library modules built in.

Nix is the latin word for snow. Nix "flakes" are a way to combine multiple flakes as inputs as well as pin their version. Kind of like pipenv/requirements.txt or "cargo lock" or "yarn lock" but for anything.

The output of derivations go in the "nix store" which is a path like /nix/store/<hash>/, so all sorts of software can co-exist (think multiple incompatible versions of the same library) and can be referenced in a fixed way.

Any kind of software can be packaged as a ".nix" file. It's really common to make a "shell" for software. For example, today I wanted to run GIMP (the image editor). I didn't have to install it in a traditional sense. Instead, I ran 'nix shell nixpkgs#gimp -c gimp'. That makes a shell environment for the "nixpkgs#gimp" derivation, including adding /nix/store/12naig12mnhrzpn88bvvw2vakyd18sjq-gimp-2.10.34/bin to PATH, and runs a shell script command (gimp). Nix makes sure to fetch all the outputs and runtime dependencies of the gimp package for me (which are cached locally and on the internet).