Skip to content

Writing Overlays

Overview

An overlay is a function final: prev: { … } that adds a layer to the nixpkgs fixed point. You return a fragment of the package set—new attributes and replacements—without editing the upstream tree.

Overlay vs override: an overlay reshapes the whole package set. .override / .overrideAttrs return one new derivation and change nothing else in pkgs unless you wire that value in (often inside an overlay). Prefer an overlay when dependents must see the same change via final; prefer a bare override for a one-off in a shell or module. See Overlay vs Override.

For the concept and fixed-point mechanics, see Overlay and Overlays pattern. For patch lists and override APIs, see Patches and overrides.

Details

Shape

Newer code uses final / prev; older code often uses self / super. The return value should look like a slice of all-packages.nix: top-level names mapping to derivations or nested sets.

final: prev: {
  myTool = prev.callPackage ./my-tool.nix { };
  hello = prev.hello.overrideAttrs (old: {
    pname = old.pname + "-patched";
  });
}

Overlays merge with shallow //: later layers replace top-level keys from earlier ones. Nested attrsets are not merged recursively.

final vs prev

Argument Meaning Use for
final The composed set after this overlay and all later overlays Dependencies of packages you define or override
prev The set from nixpkgs and overlays before this one The package you are overriding; helpers such as callPackage

Canonical manual example—dependencies from final, original recipe and callPackage from prev:

final: prev: {
  boost = prev.boost.override { python = final.python3; };
  rr = prev.callPackage ./pkgs/rr { stdenv = final.stdenv_32bit; };
}

Order

Overlays apply in list order. If two set python3, the later one wins at the top level. Put foundational pins (interpreters, stdenv, BLAS providers) before overlays that depend on them. See Pinning for revision pins; overlays pin attributes inside a given nixpkgs import.

Installing overlays

Explicit import — if you pass overlays, nixpkgs does not look up path-based overlay files:

import <nixpkgs> {
  overlays = [ myOverlay anotherOverlay ];
}

Do not use that pattern inside nixpkgs. pkgs.extend / pkgs.appendOverlays recompute the fixpoint and are expensive; prefer overlays at import time.

NixOSnixpkgs.overlays applies to the system’s nixpkgs evaluation only. It does not affect standalone nix-env or ad-hoc import <nixpkgs> unless you share the same list.

Path lookup (when overlays is not passed), in order:

  1. <nixpkgs-overlays> on NIX_PATH, if set
  2. Else ~/.config/nixpkgs/overlays.nix (a list of overlays) or ~/.config/nixpkgs/overlays/ (.nix files and subdirs with default.nix, lexicographic order)—error if both exist

Reuse one file as both nixpkgs.overlays and ~/.config/nixpkgs/overlays.nix so NixOS and user tools stay aligned.

Legacy packageOverrides

packageOverrides is roughly an overlay that only receives prev. Prefer overlays for anything you might share, layer, or install from overlays.nix.

Examples

Add a local package.

final: prev: {
  myCli = prev.callPackage ./tools/my-cli.nix {
    inherit (final) lib openssl;
  };
}

Pin a top-level interpreter for the whole import.

final: prev: {
  python3 = prev.python312;
}

Override one package’s derivation attrs (set-wide).

final: prev: {
  hello = prev.hello.overrideAttrs (old: {
    patches = (old.patches or [ ]) ++ [ ./hello-fix.patch ];
  });
}

Stack two overlays (base pin, then dependent tweak).

import <nixpkgs> {
  overlays = [
    (final: prev: { python3 = prev.python312; })
    (final: prev: {
      myApp = prev.myApp.override { python3 = final.python3; };
    })
  ];
}

NixOS + user config — same overlay list:

# configuration.nix
{ ... }: {
  nixpkgs.overlays = import ./overlays.nix;
}
# overlays.nix — also usable as ~/.config/nixpkgs/overlays.nix
[
  (final: prev: { /* … */ })
]

References

See also