with apologies

Pinning packages

· 3 min read · January 12, 2026 · #tech #linux #nixos

I run NixOS for the time being, usually tracking unstable. As a result, I have from time to time found myself wanting to pin a package to a particular (older) version because a package update doesn’t work, or at least doesn’t work for me.

Given what I understand NixOS’ intention to be—encapsulation of state, eschewing the convenience of the Filesystem Hierarchy Standard (FHS) for a layout that allows multiple versions of the same package to exist alongside each other—I always assumed this would be fairly straightforward. Just specify the version of the package rather than accepting the default from the channel, and off you go with all dependencies neatly installed alongside whatever else there is.

Unfortunately not. And the amount of half-written, possibly once working, now incomplete or just wrong hints at solutions that are out there is something I have found infuriating.1

I needed to do this again last week because something happened with the latest wireplumber. And this time I managed to make it work, so again, recording it here for future-me and anyone else who might find it useful.2

Setup is one that I think is reasonably common: I have a Nix flake that declares a set of systems; each system references a per-machine set of modules; each module then pulls in a configuration that installs and configures some packages in the usual way.

So my laptop’s default.nix now contains the following two let declarations specifying the nixpkgs repository version with the correct (in this case, previous) wireplumber package plus the package itself within that repository. The declarations that then cause wireplumber to be installed then just have to override the wireplumber.package to use the pinned one just declared.

{
  inputs,
  lib,
  pkgs,
  options,
  ...
}:

let
  ...
  wireplumber_0_5_12_pkgs = import (builtins.fetchTree {
    type = "github";
    owner = "nixos";
    repo = "nixpkgs";
    rev = "871b9fd269ff6246794583ce4ee1031e1da71895";
  }) { inherit (pkgs) system; };
  wireplumber_0_5_12 = wireplumber_0_5_12_pkgs.wireplumber;
in

  ...
  services.pipewire = {
    enable = true;
    ...
    wireplumber = {
      enable = true;
      package = wireplumber_0_5_12;
    };
  };

  ...
  system.stateVersion = "24.05";
}

To get the repo details, I initially used https://lazamar.co.uk/nix-versions/?channel=nixpkgs-unstable&package=wireplumber but that seems only up-to-date to wireplumber 0.5.10, whereas the previous version should be 0.5.12.

So to find the correct repo revision, I went back to https://search.nixos.org/packages?channel=25.11&query=wireplumber to find the latest stable version, clicked on the Source link to take me to https://github.com/NixOS/nixpkgs/blob/nixos-25.11/pkgs/development/libraries/pipewire/wireplumber.nix#L89, realized that was in 25.11 so visited Releases/Tags > Tags > 25.11 which linked to https://github.com/NixOS/nixpkgs/commit/871b9fd269ff6246794583ce4ee1031e1da71895—giving me the commit ref to use above.

Probably, surely, easier ways to do this, but this way seemed to work for me.

1

Seriously, if it’s so simple that you start your suggestion with “Just do something like …”, how about you post something a bit like a minimal working example? Or at least a reasonably complete fragment? It’s as bad as paper reviewers that baldly state “this work is not novel” without providing any pointers to the earlier work that invalidates the novelty.

2

Though, noting my comment above, with no guarantees that it will work for you, now or ever, or that I’ll keep it up-to-date. This is a blog, of sorts, not a manual.