Dogfood a Reusable Module
to dogfood: test one's own product by using it for your own purposes
You can distribute reusable module logic through flakes using flake attributes, and that includes flakeModules
.
However, importing from self
is not possible, because such an import could affect the self
attribute set.
To use your own exported module, you have to reference it directly.
┌─────────┐ ┌───────────────────────────────────┐
│ imports │ │ config.flake.flakeModules.default │
└─────┬───┘ └─────────────────┬─────────────────┘
│ │
│ ┌──────────────────┘
│ │
┌─────▼──────▼─────┐
│ flake-module.nix │
└──────────────────┘
If your module does not need anything from the local flake's lexical scope, you might implement the references in the diagram above.
But if you do need to reference, say, a package from your local flake, then you need to apply one of the solutions from Define a Module in a Separate File.
Instead of the arrows joining at the file name, we'll need a let
binding.
┌─────────┐ ┌───────────────────────────────────┐
│ imports │ │ config.flake.flakeModules.default │
└─────┬───┘ └─────────────────┬─────────────────┘
│ │
│ ┌─────────────────┘
│ │
┌─────▼───────▼─────────┐
│ let flakeModule = ... │
└─────────┬─────────────┘
│
│
│
┌─────────▼────────┐
│ flake-module.nix │
└──────────────────┘
Example with importApply
Here's an example of how this looks using the importApply
technique.
This flake shows how to export a flake module that references its own flake, instead of just the user's flake (which would be available in the module arguments).
The example only demonstrates the principle, by reexporting a locally defined package in the user's flake.
flake.nix
:
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
};
outputs = inputs@{ flake-parts, ... }:
flake-parts.lib.mkFlake { inherit inputs; } ({ withSystem, flake-parts-lib, ... }:
let
inherit (flake-parts-lib) importApply;
flakeModules.default = importApply ./flake-module.nix { inherit withSystem; };
in
{
imports = [
flakeModules.default
# inputs.foo.flakeModules.default
];
systems = [ "x86_64-linux" "aarch64-darwin" ];
perSystem = { pkgs, ... }: {
packages.default = pkgs.hello;
};
flake = {
inherit flakeModules;
};
});
}
flake-module.nix
:
# The importApply argument. Use this to reference things defined locally,
# as opposed to the flake where this is imported.
localFlake:
# Regular module arguments; self, inputs, etc all reference the final user flake,
# where this module was imported.
{ lib, config, self, inputs, ... }:
{
perSystem = { system, ... }: {
# A copy of hello that was defined by this flake, not the user's flake.
packages.greeter = localFlake.withSystem system ({ config, ... }:
config.packages.default
);
};
}
The "Factor it out" technique is equally applicable; replace importApply
by an inline module.