Flake Parts

From NixOS Wiki

Flake Parts is a framework that leverages the NixOS module system to write modular and organized flakes. It provides options that represent standard flake attributes and establishes an easy way to work with system. It is a minimal and very lightweight mirror of the flake schema.

The major benefit of flake-parts is being able to write modular flakes with the full power of the module system. It is a great option and alternative to flake-utils, a wrapper which is largely discouraged from being used.

There is documentation available for a variety of flake-parts powered modules available on https://flake.parts.

Getting Started

It is very easy to introduce flake-parts into your already existing flake.nix, or to a completely new project as well. A minimal template is provided below:

{
  description = "Your new project, powered by flake-parts!";

  inputs = {
    flake-parts.url = "github:hercules-ci/flake-parts";
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; # This should point to whichever nixpkgs rev you want.
  };

  outputs = { flake-parts, ... } @ inputs: flake-parts.lib.mkFlake { inherit inputs; } {
    imports = [
      # ./module.nix
      # inputs.foo.flakeModule
    ];

    perSystem = { config, self', inputs', pkgs, system, ... }: {
      # Allows definition of system-specific attributes
      # without needing to declare the system explicitly!
      #
      # Quick rundown of the provided arguments:
      # - config is a reference to the full configuration, lazily evaluated
      # - self' is the outputs as provided here, without system. (self'.packages.default)
      # - inputs' is the input without needing to specify system (inputs'.foo.packages.bar)
      # - pkgs is an instance of nixpkgs for your specific system
      # - system is the system this configuration is for

      # This is equivalent to packages.<system>.default
      packages.default = pkgs.hello;
    };

    flake = {
      # The usual flake attributes can be defined here, including
      # system-agnostic and/or arbitrary outputs.
    };

    # Declared systems that your flake supports. These will be enumerated in perSystem
    systems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ];
  };
}

Writing Modules

Modules are written in exactly the same way as NixOS modules. The main exposed attributes are perSystem and flake. You can reference the self and inputs attribute at the top-level, though generally you will likely not need it. An example of writing a module can be seen below:

# flake/packages.nix
{ self, inputs, ... }: {
  perSystem = { pkgs, ... }: {
    packages.hello = pkgs.hello;
  };
}

The above module can then be imported and referenced in the main flake (or other modules)

# flake.nix
{
  inputs = {
    flake-parts.url = "github:hercules-ci/flake-parts";
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
  };

  outputs = { flake-parts, ... } @ inputs: flake-parts.lib.mkFlake { inherit inputs; } {
    imports = [
      ./flake/packages.nix
    ];

    systems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ];
  };
}

On evaluation the flake will expose 4 distinct outputs under packages:

$ nix flake show --all-systems
path:/path/to/flake.nix?lastModified=omitted&narHash=omitted
└───packages
    ├───aarch64-darwin
    │   └───hello: package 'hello-2.12.1'
    ├───aarch64-linux
    │   └───hello: package 'hello-2.12.1'
    ├───x86_64-darwin
    │   └───hello: package 'hello-2.12.1'
    └───x86_64-linux
        └───hello: package 'hello-2.12.1'

See also