Nix, the shell bootstrapper
Tags: nix, node, todayilearned, devops
Published: 2020-07-19 16:58:21

So recently I swapped out Arch Linux for NixOS, mainly because [I could bootstrap my entire PC with a configuration file](https://github.com/itshaydendev/starnix). I never really looked into nix as a tool until today. Of course, I've been using nix as a package manager for about a month due to NixOS, but I'd never looked into nix itself for development purposes. And oh boy, was I glad that I did. And here's why.

---

```nix
with import <nixpkgs> {};

stdenv.mkDerivation {
  name = "node";
  buildInputs = [
    nodejs
  ];
  shellHook = ''
    export PATH="$PWD/node_modules/.bin/:$PATH"

    alias run='npm run'
  '';
}
```

So what the fork is this?! Well, calm down a little and I'll tell you.

This beautiful piece of functional code you see before you is a Nix Derivation. It's used in this instance to make a complete dev environment for me for nodejs. It lives in a file called `default.nix`, and allows for *anyone* to just come along and run `nix-shell` and have a full Node.js development environment complete with an alias of `npm run` to `run`.

The fact that I can do this without having to go download NVM or nodenv or similar is... Well, let's just be calm and say it saves me a lot of headaches.

So let's break that file down.

---

```nix
with import <nixpkgs> {};
```

This tells Nix to import the [`nixpkgs`](https://github.com/nixos/nixpkgs) package registry, which is the official source for nix packages. This becomes important later.

---

```nix
stdenv.mkDerivation {
  # ...
}
```

Does what it says on the tin really. Makes a new nix derivation, defined & configured by the contents of the block. This is what Nix evaluates to produce our dev environment.

---

```nix
name = "node";
```

This just gives our derivation a name, duh. I've called it `node` here, but you could call it `stopwritingpostsondevyoudontknowanything` for all I care.

---

```nix
buildInputs = [
  nodejs
];
```

This is where that `nixpkgs` import line comes in handy. This is telling Nix to install the latest LTS version (at least the current LTS version recorded in the nixpkgs repo) of Node.js, and make it available to us in the dev environment. You could add anything here. Need to build native extensions? Throw `gcc` and `automake` in here!

---

```nix
shellHook = ''
  export PATH="$PWD/node_modules/.bin/:$PATH"

  alias run='npm run'
'';
```

So this is essentially a bash script that will be called when the environment is created. In this instance, it's adding the `node_modules/.bin` directory to our `PATH` variable, so we can call any NPM-installed binaries as if they were globally installed on our system. Really cool for those obscure linting commands you only ever need to run once or twice.

It also aliases `npm run` to `run`, allowing me to do `run build` instead of `npm run build`. Tiny amount of time saved, but I love tiny, insignificant time saving measures.

---

So that's the `default.nix` file covered.

But Hayden, you keep telling me how cool and epic and amazing and \<insert other synonym for 'cool' here\>, but you haven't shown me anything yet.

no talk me, i angy.

Well, don't be so angy. You want a demo putting it all together? Have one.

[![asciinema](https://asciinema.org/a/T4Z8hQ9t4NZCohSjdTHJgmFjg.png)](https://asciinema.org/a/T4Z8hQ9t4NZCohSjdTHJgmFjg)

See? It's fantastic.

Well, that about wraps this up.

TL;DR, Nix is brilliant and you should try it out now. Go. Leave the room please. Go. I don't want you around anymore. Go try Nix. Now. BYE!