Setting up a Custom Nix Channel

Savanni D'Gerinel 13 Sep, 2019

Happy Friday the 13th, everyone!

This week has gone extremely well, with me finishing a project for work that will actcually help save lives. Lots of lives. And I for the life of me cannot actually think of any way in which the application can be used to create harm.

At the same time, I’m tuning my tools, and this week, that means my shell.

I’ve been working on switching my shell environment away from being a nix-shell all the time and back to being something more like the config.nix based environment that the Nix maintainers envisioned.

In the midst of this, I decided that it would also be good for me to grab all of the derivations that I’ve been duplicating from one project repository to another, and drop them into a custom nix channel.

I describe all of my development environments in a shell.nix file that I keep with the application that I’m developing. Part of my discpline also involves standardizing on a particular version of my tools, such as Rust-1.33 instead of whatever version of Rust is currently available in the public NixPkgs repository. Until this week, that meant keeping a Rust derivation file in the project repository. That inevitably leadf to me duplicating gthat derivation file (and Node, and other things), across a variety of repositories.

This was probably optional with my work repositories, but the repositories I build for Luminescent Dreams ship with the shell.nix and default.nix, and so have to also ship with the other derivations.

My own custom channel became the obvious solution, but I did not think of it until late last week.

So, while the format is actually very straightforward, I did not find documentation on how to set up the channel repository and for a while did not think of the simplest, most obvious way of finding out the format. So, here I document it all.

You will start out by building a very simple derivation set in a default.nix file:

{ system ? builtins.currentSystem }:
  pkgs = import <nixpkgs> { inherit system; };
  self = in self
in rec {
    rust_1_33_0 = pkgs.callPackage ./pkgs/dev/rust-1.33 {
      inherit pkgs;

    nodejs_9_10_0 = pkgs.callPackage ./pkgs/dev/node9.nix {
      inherit pkgs;

Every element in this set; in this case rust_1_33_0, nodejs_9_10_0, and so forth; will be available in the channel.

Next, make sure you actually define he derivations described here. Errors won’t be detected until somebody who subscribes to the channel actually tries to install something. Obvious errors, like failing to pass a parameter to a derivation, will completely break the channel and are thus easy to find.

Finally, move one directory up from your default.nix, and tar the entire directory:

> ls -l

total <whatever>
drwxr-xr-x 4 savanni staff  128 Sep 12 11:02 nixpkgs

I actually do not know whether the name of the directory matters, but I mimicked the naming convention that I found in the main nixpkgs channels. Tar up the nixpkgs directory, with bz2 compression, to the file nixexprs.tar.bz2:

> tar -cjf nixexprs.tar.bz2 nixpkgs

Finally, upload nixpkgs.tar.bz2 to a public location. This file alone is all it takes to make a channel.

To use the channel, add it to your nix channel list, but be sure to include the exact url. For instance, to get my Luminescent Dreams channel, this is your command:

nix-channel --add luminescent-dreams

My Channel

I am now running my own custom channel for Luminescent Dreams, in which I distribute both the exact versions of the tools that I use and the software that I develop. As of today, that includes:

  • rust-1.33.0
  • nodejs-9.10.0
  • nodejs-10.15.3
  • ansible-2.7.4
  • certbot-0.19.0
  • packer-1.1.3
  • terraform-0.12.2
  • vault-1.0.1
  • fitnesstrax-0.0.1
  • fitnesstrax-0.0.2

Soon I’ll add orizentic, palimpsest, and digikam-export to the channel.

Dreamer, Shaper, Seeker, Maker