- Nix 59%
- Shell 41%
An experimental Nix library that allow flake outputs to define independently scoped dependencies.
The repository can be found on Tangled with a mirror on GitHub. The docs are hosted on poacher.dev.
How it works #
A flake calls lib.new on each output it wants independently scoped. lib.new
resolves that call's declared inputs against our own lockfile rather than the
flake's own dummy inputs, so two outputs of the same flake can have different
dependencies without forcing a consumer to download them.
lib.new #
# `self` is curried here for convenience
lib.new self {
# The unique key written to the lockfile
name = "packages-nixpkgs";
# optional, impurely defaults to `builtins.currentSystem`
system = "x86_64-linux";
# All typical flake input options are valid here
inputs.nixpkgs = {
url = "github:nixos/nixpkgs?ref=nixos-unstable";
# See "Overrides" below
override = null;
};
# Mapped to `packages.x86_64-linux.hello`
outputs = { self, nixpkgs }: {
inherit (nixpkgs.legacyPackages.x86_64-linux) hello;
};
}
Full example #
{
inputs = {
scoped-flakes.url = "github:poach3r/scoped-flakes";
# Dummy inputs to populate flake.lock, never used directly
nixpkgs-unstable.url = "github:divnix/blank";
nixpkgs-stable.url = "github:divnix/blank";
};
outputs = inputs: let
inherit (inputs.scoped-flakes.lib) new overrideInput;
# This is what I mean by convenience.
ourNew = new inputs.self;
in {
# Scoped to unstable nixpkgs only.
packages.x86_64-linux = ourNew {
name = "packages-nixpkgs";
inputs.nixpkgs = {
url = "github:nixos/nixpkgs?ref=nixos-unstable";
# Automatically uses our top-level nixpkgs-unstable when a consumer
# `follows` a real input.
override = overrideInput inputs.nixpkgs-unstable;
};
outputs = { nixpkgs, ... }: {
inherit (nixpkgs.legacyPackages.x86_64-linux) hello;
};
};
# Scoped to stable nixpkgs only. A consumer who only uses `packages`
# never pulls this one in.
devShells.x86_64-linux = ourNew {
name = "devshells-nixpkgs";
inputs.nixpkgs = {
url = "github:nixos/nixpkgs?ref=nixos-25.05";
override = overrideInput inputs.nixpkgs-stable;
};
outputs = { nixpkgs, ... }: {
default = nixpkgs.legacyPackages.x86_64-linux.mkShell { };
};
};
};
}
A consumer of this flake can override just one of the two scoped dependencies:
{
inputs = {
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-25.05-small";
project = {
url = "github:bar/foo";
inputs.nixpkgs-unstable.follows = "nixpkgs";
};
};
outputs = { project, ... }: {
apps.x86_64-linux = project.packages.x86_64-linux.default;
};
}
Overrides #
new doesn't inspects your flake input to determine if its been overriden,
however, we do provide helpers for you to write it yourself:
lib.isBlank input—trueifinputcarries none of a real flake's outputslib.overrideInput input—nullifisBlank input, elseinput
override = lib.overrideInput inputs.someDummyInput; is the usual shape: it'll
pass null when the dummy is still blank, or the real resolved flake when a
consumer has overridden it via follows.
lib.forAllSystems #
Calling new once per system can be cumbersome, so we provide a helper to
makes scoped-flakes easier to use in multi-system flakes:
let
forAllSystems = scoped-flakes.lib.forAllSystems {
inherit self;
# defaults to ["x86_64-linux" "aarch64-linux" "aarch64-darwin"]
systems = ["x86_64-linux" "aarch64-linux"];
};
in {
packages = forAllSystems (system: {
name = "packages-${system}";
inputs.nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
outputs = { nixpkgs, ... }: {
inherit (nixpkgs.legacyPackages.${system}) hello;
};
});
}
The lockfile #
scoped-flakes.lock.json is committed to your repo just like your flake.lock.
It's a two-level structure where entries.<name>.<input> is a narHash
reference and resolved.<narHash> holds the actual pin. Don't edit this by
hand please.
Updating pins #
# re-pin every call-site
nix run github:poach3r/scoped-flakes#update
# re-pin all inputs of a specific output
nix run github:poach3r/scoped-flakes#update -- --name packages-nixpkgs
# re-pin a specific input
nix run github:poach3r/scoped-flakes#update -- --input sha256-MYiI+CzL0tuWgRPjGsKCDHqYs2T3OzMlMQWOYWG0qso=
# targets a specific path (default: .)
nix run github:poach3r/scoped-flakes#update -- .