Core of a distributed framework for writing Nix Flakes.
flake-parts provides the options that represent standard flake attributes and establishes a way of working with system. Opinionated features are provided by an ecosystem of modules that you can import.
Flakes are configuration. The module system lets you refactor configuration into modules that can be shared.
It reduces the proliferation of custom Nix glue code, similar to what the module system has done for NixOS configurations.
Unlike NixOS, but following Flakes' spirit, flake-parts is not a
monorepo with the implied goal of absorbing all of open source, but rather
a single module that other repositories can build upon, while ensuring a
baseline level of compatibility: which core attribute make up a flake and
how these are represented as module options.
If your project does not have a flake yet:
nix flake init -t github:hercules-ci/flake-partsOtherwise, add the input,
flake-parts.url = "github:hercules-ci/flake-parts";
flake-parts.inputs.nixpkgs.follows = "nixpkgs";
then slide mkFlake between your outputs function head and body,
outputs = { self, flake-parts, ... }:
flake-parts.lib.mkFlake { inherit self; } {
flake = {
# Put your original flake attributes here.
};
systems = [
# systems for which you want to build the `perSystem` attributes
"x86_64-linux"
# ...
];
};
Now you can add the remaining module attributes like in the the template.
See the template.
See flake.parts
-
config,options,lib, ...: standard module system parameters. -
getSystem: function from system string to theconfigof the appropriateperSystem. -
moduleWithSystem: function that brings theperSystemmodule arguments. This allows a module to reference the defining flake without introducing global variables (which may conflict).{ moduleWithSystem, ... }: { nixosModules.default = moduleWithSystem ( perSystem@{ config }: # NOTE: only explicit params will be in perSystem nixos@{ ... }: { services.foo.package = perSystem.config.packages.foo; imports = [ ./nixos-foo.nix ]; } ); }
-
withSystem: enter the scope of a system. Worked example:{ withSystem, ... }: { # perSystem = ...; nixosConfigurations.foo = withSystem "x86_64-linux" (ctx@{ pkgs, ... }: pkgs.nixos ({ config, lib, packages, pkgs, ... }: { _module.args.packages = ctx.config.packages; imports = [ ./nixos-configuration.nix ]; services.nginx.enable = true; environment.systemPackages = [ packages.hello ]; })); }
-
pkgs: Defaults toinputs.nixpkgs.legacyPackages.${system}. Can be set viaconfig._module.args.pkgs. -
inputs': The flakeinputsparameter, but withsystempre-selected. Note the last character of the name,', pronounced "prime".systemselection is handled by the extensible functionperInput. -
self': The flakeselfparameter, but withsystempre-selected. This might trigger an infinite recursion (#22), so preferconfig. -
system: The system parameter, describing the architecture and platform of the host system (where the thing will run).
- Getting the locally defined
hellopackage on/for anx86_64-linuxhost:nix build #hello(assumingsystemshasx86_64-linux)config.packages.hello(ifconfigis theperSystemmodule argument)allSystems."x86_64-linux".packages.hello(assumingsystemshasx86_64-linux)(getSystem "x86_64-linux").packages.hello)withSystem "x86_64-linux" ({ config, ... }: config.packages.hello)
Why so many ways?
- Flakes counterintuitively handles
systemby enumerating all of them in attribute sets.flake-partsdoes not impose this restriction, but does need to support it. flake-partsprovides an extensible structure that is richer than the flakes interface alone.