(dependency-management-npins)=
The Nix language describes dependencies between files that Nix manages. Nix expressions themselves can depend on remote sources, and there are multiple ways to specify their origin, as shown in .
For more automation around handling remote sources, set up npins in your project:
$ nix-shell -p npins --run "npins init --bare; npins add github nixos nixpkgs --branch nixos-23.11"
This command will fetch the latest revision of the Nixpkgs 23.11 release branch.
In the current directory it will generate npins/sources.json, which will contain a pinned reference to the obtained revision.
It will also create npins/default.nix, which exposes those dependencies as an attribute set.
Import the generated npins/default.nix as the default value for the argument to the function in default.nix and use it to refer to the Nixpkgs source directory:
{
sources ? import ./npins,
system ? builtins.currentSystem,
pkgs ? import sources.nixpkgs { inherit system; config = {}; overlays = []; },
}:
{
package = pkgs.hello;
}nix-build will call the top-level function with the empty attribute set {}, or with the attributes passed via --arg or --argstr.
This pattern allows overriding remote sources programmatically.
Add npins to the development environment for your project to have it readily available:
{
sources ? import ./npins,
system ? builtins.currentSystem,
pkgs ? import sources.nixpkgs { inherit system; config = {}; overlays = []; },
}:
-{
+rec {
package = pkgs.hello;
+ shell = pkgs.mkShellNoCC {
+ inputsFrom = [ package ];
+ packages = with pkgs; [
+ npins
+ ];
+ };
}Also add a shell.nix to enter that environment more conveniently:
(import ./. {}).shellSee for details, and note that here you have to pass an empty attribute set to the imported expression, since default.nix now contains a function.
(overriding-sources-npins)=
As an example, we will use the previously created expression with an older version of Nixpkgs.
Enter the development environment, create a new directory, and set up npins with a different version of Nixpkgs:
$ nix-shell
[nix-shell]$ mkdir old
[nix-shell]$ cd old
[nix-shell]$ npins init --bare
[nix-shell]$ npins add github nixos nixpkgs --branch nixos-21.11
Create a file default.nix in the new directory to import the original one with the sources you just created.
import ../default.nix { sources = import ./npins; }This will result in a different version being built:
$ nix-build -A build
$ ./result/bin/hello --version | head -1
hello (GNU Hello) 2.10
Sources can also be overridden on the command line:
nix-build .. -A build --arg sources 'import ./npins'
A previous version of this guide recommended using niv, a similar pin manager written in Haskell.
If you have a project using niv, you can import remote source definitions into npins:
npins import-niv
:::{warning} All the imported entries will be updated, so they won't necessarily point to the same commits as before. :::
NixOS defaults to using channels to locate nixpkgs.
You can instead pin a version using npins from the system.nix entrypoint (available since 26.05):
let
sources = import ./npins;
in
import "${sources.nixpkgs}/nixos" {
configuration = ./configuration.nix;
}Before NixOS 26.05's system.nix use:
sudo NIX_PATH="nixos-config=configuration.nix:nixpkgs=$(nix-instantiate --raw --eval npins -A nixpkgs.outPath)" nixos-rebuild switchIf you use npins with system.nix, disable channels in your configuration:
# configuration.nix
{
# ...
nix.channel.enable = false;
}To make such pinned dependencies available as look-up paths (like <nixpkgs>) while using the NixOS configuration, one may use:
# configuration.nix
{ lib, ... }:
let
sources = import ./npins;
in
{
# ...
nix.nixPath = lib.mapAttrsToList (k: v: "${k}=${v}") sources;
}To use the v3 command line and run programs from dependencies
exposing packages through a flake, like nix run nixpkgs#hello,
you can enable flakes and add the pins to the flake registry like:
# configuration.nix
{ lib, ... }:
let
sources = import ./npins;
in
{
# ...
experimental-features = "nix-command flakes";
nix.registry = lib.mapAttrs (_: path: {
to = {
type = "path";
inherit path;
};
}) sources;