Skip to main content

NIX HOWTO

This HOWTO assumes you already have nix installed.

Nix Channels​

We currently recommend using the Nix Unstable channel by default as it contains the latest tested updates on a rolling basis. This means that the branch for the NixOS/nixpkgs repository that is used is the nixpkg-unstable branch.

In the step above, you may need to modify the ref="{BRANCH_NAME}"; line with the master branch for the NixOS/nixpkgs repository if you encounter any Git-related errors.

Trussels using Nix for package management have run into issues related to commits not being found on that specific nixpkgs-unstable branch. The nix-package-search will report the ref to be nixpkgs-unstable but the actual commit may not exist on that branch due to integration errors within the NixOS/nixpkgs repository that eventually may correct itself.

To read up on Nix Channels, see their documentation. While the branch nixpkgs-unstable specifically lags behind master to thoroughly test things, some of our Truss projects are required to be up-to-date. This means that we may need to update some ref=""; sections of the Import statement to point to master to upgrade or downgrade a single package in order to maintain our obligations to keep our dependencies up-to-date.

Setting up a new project​

  1. Create a nix directory

    mkdir -p ./nix

  2. Create nix/update.sh with the content below and make the script executable

    #!/usr/bin/env bash

    set -euo pipefail

    if [ -z "${NIX_PROFILE+x}" ]; then
    echo "NIX_PROFILE not set, not installing globally"
    echo "Try running 'direnv allow'"
    exit 1
    fi

    # Having NIX_SSL_CERT_FILE set means go won't use macOS keychain based certs
    # MOST projects can leave this alone, but if you unset it in `.envrc`
    # be sure to uncomment the following line
    # export NIX_SSL_CERT_FILE=$HOME/.nix-profile/etc/ssl/certs/ca-bundle.crt

    DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
    # install packages
    nix-env -f "${DIR}" -i
    # Store a hash of this file to the hash of the nix profile
    # This way if the config changes, we can warn about it via direnv
    # See the nix config in .envrc
    config_hash=$(nix-hash "${DIR}")
    store_hash=$(nix-store -q --hash "${NIX_PROFILE}")
    echo "${config_hash}-${store_hash}" > "${DIR}/../.nix-hash"
  3. Create a nix/default.nix that looks like the below, but replace _YOUR_PROJECT_NAME_ with the name of your project

    let
    pkgs = import <nixpkgs> {};
    inherit (pkgs) buildEnv;
    in buildEnv {
    name = "_YOUR_PROJECT_NAME_-packages";
    paths = [
    ];
    }
  4. Create/add to your .envrc with the following, replacing _YOUR_PROJECT_NAME_

    # if nix is installed, use it
    if [ ! -r .nix-disable ] && has nix-env; then
    # set NIX_PROFILE so nix-env operations don't need to manually
    # specify the profile path
    export NIX_PROFILE="/nix/var/nix/profiles/per-user/${LOGNAME}/_YOUR_PROJECT_NAME_"

    # Having NIX_SSL_CERT_FILE set means go won't use macOS keychain
    # based certs
    # MOST projects can leave this set, but if you are using go and
    # custom certificates, you might need to futz with this
    # export NIX_SSL_CERT_FILE_ORIG=$NIX_SSL_CERT_FILE
    # unset NIX_SSL_CERT_FILE

    nix_dir="nix"
    # add the nix files so that if they change, direnv needs to be reloaded
    watch_file "${nix_dir}"/*.nix
    config_hash=$(nix-hash "${nix_dir}")
    store_hash=$(nix-store -q --hash "${NIX_PROFILE}")

    # The .nix-hash file is created by nix/update.sh
    if [ ! -r .nix-hash ] || ! grep -q "${config_hash}-${store_hash}" .nix-hash; then
    log_status "WARNING: nix packages out of date. Run ${nix_dir}/update.sh"
    fi

    # add the NIX_PROFILE bin path so that everything we just installed
    # is available on the path
    PATH_add ${NIX_PROFILE}/bin

    # If you use go, add this
    #
    # nix is immutable, so we need to specify a path for local changes, e.g.
    # binaries can be installed local to this project
    export GOPATH=$PWD/.gopath
    PATH_add ./.gopath/bin

    # If you use node, add this
    #
    PATH_add ./node_modules/.bin
    export NPM_CONFIG_PREFIX=$PWD/.npmglobal
    PATH_add ./.npmglobal/bin

    fi
  5. Use nix-package-search to find your package versions and add them to your nix/default.nix in the paths section. Your new default.nix might look something like (with NAME replaced with your project)

    let
    pkgs = import <nixpkgs> {};
    inherit (pkgs) buildEnv;
    in buildEnv {
    name = "_YOUR_PROJECT_NAME_-packages";
    paths = [

    (import (builtins.fetchGit {
    # Descriptive name to make the store path easier to identify
    name = "nodejs-14.17.0";
    url = "https://github.com/NixOS/nixpkgs/";
    ref = "refs/heads/nixpkgs-unstable";
    rev = "b65a64086f8c136545955d447e1918b97dad02af";
    }) {}).nodejs-14_x
    ];
    }
  6. Use direnv allow to set up the new environment variables

  7. Run ./nix/update.sh to install the packages. It might take a while the first time and there isn't a progress bar or anything to let you know it's working

  8. When the update script finishes, you are ready to go

  9. You can then update nix/default.nix when you need to add/update packages and then direnv will let you know your packages are out of date and you need to run ./nix/update.sh