Skip to content

Instantly share code, notes, and snippets.

@milibopp
Last active April 29, 2020 19:44
Show Gist options
  • Save milibopp/47fa7db73689f2362300e61e35a95e6b to your computer and use it in GitHub Desktop.
Save milibopp/47fa7db73689f2362300e61e35a95e6b to your computer and use it in GitHub Desktop.

This guide takes you through your first steps with the Nix package manager.

While NixOS is a Linux distribution based on Nix, you can install Nix on other Linux distributions, MacOS and Windows via WSL using the install script from our website:

curl -L https://nixos.org/nix/install | sh

should we link to GPG verification for concerned users?

Check that the installation was successful by running

nix-channel --list

This shows you the package distribution channel used by Nix. By default, this is https://nixos.org/channels/nixpkgs-unstable

Shell environments

Nix can create reproducible environments given a declarative configuration called a Nix expression. Reproducible means you can share the configuration with others and guarantee that they are using the same software as you.

To get started, create a file called shell.nix in a new folder with the following contents:

with import <nixpkgs> {};

mkShell {
  buildInputs = [
    which
    htop
  ];
}

To enter this environment, use nix-shell inside your folder

nix-shell

The command will start downloading the missing packages from the cache. This may take a few moments. When it is done, you are dropped into a new shell. This shell contains makes the packages you specified in the config available.

Run htop to confirm it is present. You can quit by pressing q.

Next run which htop to check where the htop command is on-disk. You should see something similar to this:

/nix/store/y3w2i8kfdbfj9rx287ad52rahjpgv423-htop-2.2.0/bin/htop

This is the path to the binary in the Nix store. Nix installs all packages into the store using a combination of its hash, name and version.

You can search for available packages using nix search, for example:

nix search python3
nix search nodejs
nix search ghc
nix search cargo

Setup a development environment

Python is used as an example here. But we could let the reader choose between different tech stacks and application domains.

As an exercise, let us build a Python web application using the Flask web framework.

Create a new file default.nix. This is file is conventionally used for specifying packages

{ pkgs ? import <nixpkgs> {} }:

pkgs.python3Packages.buildPythonApplication {
  pname = "myapp";
  src = ./.;
  version = "0.1";
  propagatedBuildInputs = [ pkgs.python3Packages.flask ];
}

You will also need a Flask app as main.py:

#! /usr/bin/env python

from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello, Nix!"

if __name__ == "__main__":
    app.run(host='0.0.0.0')

and a setup.py script:

from distutils.core import setup

setup(name='myapp', version='0.1', scripts=['main.py'])

Now build the package with:

nix-build

This will create a symbolic link result to our package's path in the Nix store, which looks like /nix/store/6i4l781jwk5vbia8as32637207kgkllj-myapp-0.1. Look around to see what is inside ;)

You may notice we can run the application from the package like ./result/bin/main.py. We can still use the default.nix as a shell environment to get the same result:

nix-shell default.nix
python3 main.py

In this context, Nix takes on the role that you would otherwise use pip or virtualenv for. Nix installs required dependencies and separates the environment from others on your system.

You can check this Nix configuration into version control and share it with others to make sure you are all running the same software. Especially with many dependencies this is a great way to prevent configuration drift between different team members & contributors.

Build a Docker container

For this section we assume you have Docker installed.

Now that you have package a Flask app, you may want to deploy it. One way to do this is to package it as a Docker container that can be hosted on a container hosting platform.

Nix comes with tools for building Docker containers. To turn our Python app into a Docker container, we only have to specify what command to run. Nix will take care of building a minimal image required to make that happen.

Create a file docker.nix:

{ pkgs ? import <nixpkgs> {} }:

let
  app = pkgs.callPackage ./default.nix {
    inherit pkgs;
  };

in pkgs.dockerTools.buildImage {
  name = "myapp";
  config = {
    Cmd = [ "${app}/bin/main.py" ];
  };
}

We are calling the expression under ./default.nix and pass it our own pkgs. Under Cmd we use the variable app to retrieve the path to the executable Python app.

Now we can build the Docker image and load it into Docker:

nix-build docker.nix
docker load --input result

This should give you an image name like myapp:hg1wd1wbj9sl9kvl9y5f3hs4pmix4vsa. Use this to run the Docker image. Also make sure to forward port 5000, so you can access the app in the browser:

docker run -it -p 5000:5000 myapp:hg1wd1wbj9sl9kvl9y5f3hs4pmix4vsa

Now you can see the site on http://localhost:5000.

Open questions

  • We could leave out shell.nix and just work on default.nix for everything. There are some different ways of setting this up, this guide should focus on the most straightforward approach.
  • How much Nix code can we show without starting to teach the language?
  • How do we accomodate multiple tech stacks? We should showcase tech stacks that we can handle well, but their could be multiple to choose from.
  • Can we rely on people having Docker installed?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment