NixOS: The DOs and DON'Ts of nixpkgs overlays

written by Christian Kauhaus on 2017-11-07

One presentation at NixCon 2017 that especially drew my attention was Nicolas Pierron's talk about Nixpkgs overlays (video, slides). I'd like to give a quick summary here for future reference. All the credits go to Nicolas, of course.

What are overlays?

Overlays are the new standard mechanism to customize nixpkgs. They replace constructs like packageOverride and overridePackages.

How do I use overlays?

Put your overlays into ~/.config/nixpkgs/overlays. All overlays share a basic structure:

self: super: {
  …
}
Arguments:

  • self is the result of the fix point calculation. Use it to access packages which could be modified somewhere else in the overlay stack.
  • super one overlay down in the stack (and base nixpkgs for the first overlay). Use it to access the package recipes you want to customize, and for library functions.

Good examples

Add default proxy to Google Chrome

self: super:
{
   google-chrome = super.google-chrome.override {
     commandLineArgs =
       "--proxy-server='https=127.0.0.1:3128;http=127.0.0.1:3128'";
   };
}
From Alexandre Peyroux.

Fudge Nix store location

self: super:
{
  nix = super.nix.override {
    storeDir = "${<nix-dir>}/store";
     stateDir = "${<nix-dir>}/var";
   };
}
From Yann Hodique.

Add custom package

self: super:
{
  VidyoDesktop = super.callPackage ./pkgs/VidyoDesktop { };
}
From Mozilla.

Bad examples

Recursive attrset

self: super: rec {
   fakeClosure = self.writeText "fake-closure.nix" ''
     …
   '';
   fakeConfig = self.writeText "fake-config.nix" ''
    (import ${fakeClosure} {}).config.nixpkgs.config
  '';
}
Two issues:

  • Use super to access library functions.
  • Overlays should not be recursive. Use self.

Surplus arguments

{ python }:
self: super:
{
  "execnet" =
    python.overrideDerivation super."execnet" (old: {
      buildInputs = old.buildInputs ++ [ self."setuptools-scm" ];
    });
}
The issue:

  • Overlays should depend just on self and super in order to be composeable.

Awkward nixpkgs import

{ pkgs ? import <nixpkgs> {} }:
let
  projectOverlay = self: super: {
    customPythonPackages =
      (import ./requirements.nix { inherit pkgs; }).packages;
  };
in
import pkgs.path {
  overlays = [ projectOverlay ];
}
Two issues:

  • Unnecessary double-import of nixpkgs. This might break cross-system builds.
  • requirements.nix should use self not pkgs.

Improved version

shell.nix:

{ pkgsPath ? <nixpkgs> }:
import pkgsPath {
  overlays = [ import ./default.nix; ];
}
default.nix:

self: super:
{
 customPythonPackages =
   (import ./requirements.nix { inherit self; }).packages;
}

Incorrectly referenced dependencies

self: super:
let inherit (super) callPackage;
in {
  radare2 = callPackage ./pkgs/radare2 {
    inherit (super.gnome2) vte;
    lua = super.lua5;
  };
}
The issue:

  • Other packages should be taken from self not super. This way they can be overridden by other overlays.

Overridden attrset

self: super:
{
  lib = {
    firefoxVersion = … ;
  };
  latest = {
    firefox-nightly-bin = … ;
    firefox-beta-bin = … ;
    firefox-bin = … ;
    firefox-esr-bin = … ;
  };
}
The issue:

  • Other attributes present in lib and latest from down the overlay stack are erased.

Improved version

Always extend attrsets in overlays:

self: super:
{
  lib = (super.lib or {}) // {
    firefoxVersion = … ;
  };
  latest = (super.latest or {}) // {
    …
  };
}

Summary

I hope this condensed guide helps you to write better overlays. For in-depth discussion, please go watch Nicolas' talk and read the Nixpkgs manual. Many thanks to Nicolas for putting this together!


Cover image: ⓒ 2009 studio tdes / Flickr / CC-BY-2.0

Get in touch

Call us or send us an email.

Contact
mail: mail@flyingcircus.io
fon: +49 345 219 401 0
fax: +49 345 219 401 28

Address
Flying Circus Internet Operations GmbH
Leipziger Str. 70/71
06108 Halle (Saale)
GERMANY


Commercial register
AG Stendal as HRB 21169
VAT ID: DE297423633

Managing Directors:
Christian Theune, Christian Zagrodnick

flyingcircus.io — 2016-2021Privacy