1. 48
  1. 11

    I have been using NixOS exclusively on my computer for 2 years now (see my NixOS config). I also write Haskell, both at work and as hobby, using Nix instead of stack (more on that here). Ask me anything!

    1. 3

      So if I start with your NixOS config, can I get staarted with NixOS and adapt it to my needs? Is it possible to combine it with Guix?

      1. 4

        Is it possible to combine it with Guix?

        Partially. Guix is basically a fork of Nix with Scheme implanted instead of the Nix expression language. Both package managers use the same fundamental unit (Nix’s derivation), and derivation (.drv) files produced by Guix can be imported in Nix. There’s no easy way of bridging that gap though, currently. I’m also not sure if both can run off the same store.

        As for running Guix on NixOS, work is being done (albeit slowly) to enable this via a NixOS module.

        In general I’d recommend learning the Nix language instead. Even as a Lisper, I find it to be quite pleasing to work with once you get the hang of it. There’s a one-page overview over the language that I wrote a while back to help people get started, which you might find useful.

        1. 1

          Thanks for this. Your one-pager is really useful; perhaps the most accessible intro to the lanauge I’ve read. But I have to say that the Nix language makes me yearn for the clean semantics and constructs of Scheme. Rather than running Guix on Nix, wouldn’t it be easier and cleaner to write Nix on Guix? I don’t mean to start a language war here but if you put a gun to my head and asked me to unify the two approaches then i know which route I would choose.

          1. 1

            Glad to hear nix-1p helps!

            Nix has a few warts (such as the ? operator and some of its builtins), but overall seems like a fairly clean language to me.

            There’s pros and cons to each of the two approaches here. For example, Guix gets namespaces for free from Guile, which means there is a defined and queryable package set (whereas Nix just has one big attribute set that you traverse).

            The downside of this is that you now have a namespace, and declaring things into them becomes a side effect. In Nix it’s very easy (for people experienced with the language & tooling) to understand exactly which code is relevant, this becomes less clear once you have sequential execution, mutability and so on.

            My ideal setup would probably be a language with the exact semantics of Nix (purely-functional, lazy) but an S-expression syntax. That’s easy to implement, but at the moment there’s more important things to work on in the ecosystem.

        2. 2

          So if I start with your NixOS config, can I get staarted with NixOS and adapt it to my needs?

          The first step would be to make a fresh install of NixOS on your machine. And then, yea, you can fork and use my config per the instructions in README; although you don’t really need to. You can start from the NixOS base configuration.nix, and then customize it based on the tips from https://nixos.wiki/

          Is it possible to combine it with Guix?

          Nope. Guix does not even use Nix.

        3. 1

          Have you used docker inside NixOS? And if so, why?

          1. 2

            To run an one-off image from Docker registry, like mysql or redis, specific to a project. Docker is generally not required on NixOS for creating reproducible environments.

        4. 4

          I’ve found that the Nixpkgs approach to Haskell packages (choosing a subset of Hackage packages, picking one version of each which mostly work together) can often require a lot of overriding. Even worse, the error messages only appear after (re)compiling a bunch of dependencies, making each iteration painfully slow.

          IOHK’s Haskell infrastructure takes the opposite approach: running cabal or stack to solve the dependencies, then fetching and building whichever versions were chosen (unless they’re already in /nix/store, of course). I’ve found this works quite well: it requires a larger up-front build time, but is more reliable so doesn’t need hand-holding.

          1. 1

            I haven’t seen this before. Cool. Starred it and scheduled for a read on the commute.

          2. 3

            It’s good the author addresses the value of pinning channels, such as nixpkgs. Otherwise the dependencies aren’t really deterministic as nix will use the latest version.

            For me the biggest advantage of nix is that I can keep globally installed packages down to a minimum. Build dependencies are only installed/updated upon entering a nix shell.

            1. 2

              Initially I though this was just being overly cautious, especially for ad-hoc development environments for e.g. other people’s projects not catered for nix. In reality though, both projects and nixpkgs quickly advance enough to make this a legitimate problem. I’ve since started taking pinning more seriously and do for most of my projects. Especially considering an upgrade is a relatively easy task.

              For my $HOME I’ve recently moved to https://github.com/rycee/home-manager - which is sweet. But still try to keep both my global system, and user environment down to a minimum. Nix shell (combined with direnv) makes adding whatever extra tools you need very easy imo.

              1. 2

                Thanks for the nice article!

                In reality though, both projects and nixpkgs quickly advance enough to make this a legitimate problem.

                I have encountered the same (in particularly nixpkgs-unstable) and have also started pinning in projects. Until flakes are adopted, I am using niv, which is really nice for adding package sets, pinning them, and updating them.

              2. 1

                For me the biggest advantage of nix is that I can keep globally installed packages down to a minimum.

                Why is that an advantage? It would be a nightmare to me.

                1. 3

                  I go for a middle ground here. I basically have no system packages. This is just to keep the /etc/nixos/configuration.nix down to a minimum. Two reasons for wanting that: it requires superuser to change and more importantly it’s not portable to non-NixOS systems.

                  I use home-manager to port my user profile across systems. I install quite a bit of software in my user profile of course. That’s everything from editors, language servers, browsers, shell utilities, and whatnot. I also have one version of python, node, and the likes for the occasional time I need to just try stuff in a repl or other tiny experiments. However, my threshold is really low for just doing echo "use_nix -p <pkgs...>" > .envrc into a directory to give me a quick and dirty local environment to contain deps. I don’t really care that much about garbage collection and disk utilization, but having these experiments local somewhere ensures that the tools pulled in for the session are wiped at some point.

                  For projects I actually work on, I always try to define my dependencies locally to that project. For projects which aren’t mine and where I don’t want to force nix on the upstream, I have a nix-utils repository where I gather .nix files which I symlink or import in the other projects.

                  I try not to be too opinionated on this. I always assess the situation, or adapt over time. There’s no point in insisting on whats better or worse. I just want “shit to work”, while not feeling I’m compromising ergonomics.

                  1. 1

                    Applying updates is faster (less to download/install), smaller attack surface, smaller rootfs size. Just to name a few of by reasons..

                    1. 1

                      None of those things are true. The question was not about the benefit of using less software, it was about the benefit of having less global software. In the end, the amount of software you need is approximatively constant irrespective of the way you manage it. If anything, managing non-global software requires slightly more software to manage (exactly what the blog post is about). In practice, it might require even more than that since you would be more likely to use different versions of the same software simultaneously.

                      1. 1

                        In practice, it might require even more than that since you would be more likely to use different versions of the same software simultaneously.

                        Yes, but there is great thing in that - you have reproducible builds. So no more problems when for example for some developers application stopped working because they have updated DB already and some are still using old version. Think about it as a Docker-like library isolation, but without Docker. So no more problems with OpenSSL version mismatch, no more problems with custom patches to the software (as these can be stored in Nix derivations), etc. Ok, you in theory use more disk space (which can be optimised anyway) but you gain the option of making application building everywhere without worry for small but annoying incompatibilities.

                        1. 1

                          You don’t need to use NixOS to have reproducible builds.

                          You don’t need to use NixOS to use Nix.

                          You don’t need to avoid installing global packages in order to have reproducible builds. Especially on NixOS.

                          1. 1

                            Of course you do not need NixOS for that, I never said anything like that. Just Nix (with or without NixOS) make it simpler.

                            Of course you do not need NixOS to use Nix, I use Nix on my macOS.

                            Of course you do not need to avoid global installations to have reproducible builds, just do not having to do so make it less error prone (as it will not accidentally use globally installed package).

                        2. 1

                          In the end, the amount of software you need is approximatively constant irrespective of the way you manage it.

                          A competent package manager that can correctly handle dependencies will get you a long way towards this without requiring a lot of extra software.

                          None of those things are true.

                          Do you think that downloading/applying 100MB of update > applying 1GB+ of updates, or that having extraneous libraries/services installed reduces the attack surface of your system, or that somehow a rootfs that is tens of GB in size is < a rootfs measured in hundreds of MB?

                  2. 1

                    I have been using lorri. It is really nice. Setting it up with home-manager is trivial. I haven’t used it at work, sadly, where I am forced to use OS X.

                    YMMV, but for javascript tools I use yarn2nix. First, I use yarn to manage a package.json and yarn.lock. In the same directory I put the following default.nix:

                    { pkgs ? import <nixpkgs> { } }:
                    let
                      name = "javascript-tools";
                      src = ./.;
                      yarn2nix = (pkgs.callPackage (pkgs.fetchFromGitHub {
                        owner = "moretea";
                        repo = "yarn2nix";
                        rev = "2b29eafedd3822095187ba20a472c2b01642b09d";
                        sha256 = "0cvjb3n988643i7kk2fq313cfd2dbnnm5948fbh7r56fn3l5ridv";
                      }) { });
                      yarnModules = yarn2nix.mkYarnPackage {
                        inherit src;
                        name = "${name}-yarn-modules";
                        packageJSON = ./package.json;
                        yarnLock = ./yarn.lock;
                      };
                    in pkgs.stdenv.mkDerivation rec {
                      inherit name src;
                      buildCommand = ''
                        mkdir -p $out
                        ln -s ${yarnModules}/libexec/node-packages/node_modules/.bin $out/bin
                      '';
                    }
                    
                    1. 3

                      What is the advantage of using nix, to manage NPM dependencies, instead of say NPM (or Yarn, or …)?

                      1. 1

                        The main reason is that home-manager can keep my work and home machines synchronized. I use it for managing python packages and haskell packages too… I just have to jump through an extra hoop for javascript.

                        1. 1

                          Ok thanks for explaining.

                          In my experience, those packages are usually managed and pinned by lockfiles, and synced with a VCS, so the appeal of adding another layer on top of them isn’t immediately clear.

                      2. 2

                        FWIW, I use lorri and nix (not NixOS) on MacOS, and other than the install-time mess they (Apple) made of / mounts in Catalina, it’s pretty smooth.

                        1. 1

                          I’m really curious about the steps you took.

                          Right now in my home.nix I have:

                          services = if pkgs.stdenv.isLinux then { lorri.enable = true; } else { };
                          

                          Can I really change this to services.lorri.enable = true; and it will just work?

                        2. 1

                          I might go ahead and give it a try soon then!

                        3. 1

                          I were to have to use a non-Mac Unix for whatever reason, I would be living on NixOS, and using it in this way. Nix is too alien on the Mac for my tastes, but it would be perfect on a less opinionated system.

                          1. 1

                            You can use home-manager that replaces homebrew. And Nix is still useful for development environments (Mac or Unix).