Synchronizing inputs across Nix flakes
I have a few projects using nix-direnv
to load development environments automatically, and each of them is using a slightly different version of nixpkgs
, depending on when I created them. As my laptop with 256 GB storage run out of space again, and I do not depend on any unstable software with my projects, I want to synchronize their inputs to avoid duplications and reduce storage usage.
Synchronizing inputs with nix registry
As I understand it, nix registry
is just an alias to an actual input. By using an alias, you can then force multiple flakes to use the exact same version of an input.
You can define your own nix registry
specific to your machine with nix.registry
.
To create a registry that is called foo
, and points to nixos-23.05
branch in NixOS/nixpkgs
repository on GitHub, you can update your NixOS configuration as the following.
# in your configuration.nix
{ config, pkgs, lib, ... }:
{
nix.registry = {
foo.to = {
owner = "NixOS";
ref = "nixos-23.05";
repo = "nixpkgs";
type = "github";
}
};
}
And then you can use this foo
as input in Nix flake. You do not need to define this variable in inputs
, as missing inputs will be resolved by the registry automatically.
# flake.nix
{
outputs = { self, foo }:
{
};
}
Using nix.registry
can only create nix registry
on your local machine. If you want to create a registry definition that can be shared among multiple machines, you can create a JSON file according to the format accepted by nix registry
and host it somewhere, and point to that JSON file in the nixConfig.flake-registry
in your flake.nix
. A good start will be forking the global flake registry.
# flake.nix
{
outputs = { self, foo }:
{
};
nixConfig = {
flake-registry = "https://example.com/myrepository.json";
};
}
In my opinion you should always have nixConfig.flake-registry
defined if you are using nix registry
. Without defining nixConfig.flake-registry
, nix registry
will become a global mutable state. If you cannot control the nix registry
definition in your flake consumers’ machine, you cannot guarantee your flake would build there. What if foo
points to nixos-23.05
on your machine, but foo
points to nixos-14.05
on their machine? What if you have two projects using the same registry name in their flake, but that name should resolve to two entirely different inputs?
Synchronizing inputs with proxy flake
Another option to synchronize inputs is to create a proxy flake. It will be used as an input by your downstream flakes and its inputs will be followed, exposing them to downstream flakes. This approach obviously works with multiple machines.
For example, I have a flake that has the following inputs as proxy.
# flake.nix
{
description = "proxy flake for controlling input for all my flakes";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-24.11";
flake-parts = {
url = "github:hercules-ci/flake-parts";
inputs.nixpkgs-lib.follows = "nixpkgs";
};
nixos-hardware.url = "github:NixOS/nixos-hardware/master";
nur.url = "github:nix-community/NUR/master";
nur.inputs.nixpkgs.follows = "nixpkgs";
};
outputs = { self, nixpkgs }:
{
};
}
And then I can use its inputs indirectly in my projects’ flake.
# projects/flake.nix
{
inputs = {
proxy-flake.url = "github:winston0410/proxy-flake?main";
nixpkgs.follows = "proxy-flake/nixpkgs";
flake-parts.follows = "proxy-flake/flake-parts";
};
outputs = { self, nixpkgs, flake-parts }:
{
};
}
Personally I prefer using proxy flake over nix registry
, as it completely remove the possible pitfall of a global mutable state.
Upgrading inputs
To update inputs, after changing their target commit or branch in your registry definition or proxy flake, you still have to run nix flake update
manually to update downstream flakes. Even though it seems to be a hassle, inputs of your projects would not update automatically without you knowing. But of course you can write a script to automate it.
No matter which approach you have chosen, you can still find sha256
hash in flake.lock
to confirm which commit or branch does it resolve to.