Skip to content

flake-parts

Overview

flake-parts is a small library that evaluates flake.nix outputs with the Nix module system. Instead of building a large attrset by hand, you call flake-parts.lib.mkFlake { inherit inputs; } { … } and declare flake attributes as options (systems, perSystem, flake, …), optionally split across imports.

The design stays close to the flake schema: opinionated layout comes from importable modules in the ecosystem, not from a fixed monorepo convention. Flakes and the modern nix CLI remain experimental (Nix flakes + nix-command); flake-parts assumes both. It shares the module-system motivation with NixOS and Home Manager, but targets flake outputs rather than host or user configuration.

Details

mkFlake. Add flake-parts as an input, then wrap the body of outputs:

outputs = inputs@{ flake-parts, ... }:
  flake-parts.lib.mkFlake { inherit inputs; } {
    # module body
  };

The second argument is a module — an attrset, a function returning one, or a path. Definitions merge the same way as in the module system.

Systems and perSystem. List target platforms under systems. Put packages, apps, checks, and devShells under perSystem; flake-parts expands them to the conventional packages.<system>.… layout (see Packages, apps, and devShells).

Named arguments (pitfall). Module functions only receive explicitly named parameters — flake-parts uses builtins.functionArgs to decide what to pass. perSystem = args: { … } does not get pkgs unless you name it: perSystem = { pkgs, ... }: { … }. The same rule applies to flake, imports, and other module functions.

self' and inputs'. Inside perSystem, these are system-preselected views of self and inputs (e.g. inputs'.nixpkgs is already fixed to the current system). Name them when you need cross-system wiring without repeating system in every lookup.

flake and other attrs. System-independent outputs — nixosModules, overlays, nixosConfigurations, and similar — go under flake or other top-level options flake-parts declares. You can still set almost anything; some attributes have dedicated options for merging.

Wiring hosts to packages. Top-level helpers withSystem, moduleWithSystem, and getSystem connect nixosConfigurations to perSystem packages (for example, referencing a built package from a NixOS module). See module arguments in the upstream docs.

imports. Split logic into files or reuse modules from other flakes (often exposed as flakeModules.default). Local paths and attrsets both work — the main scaling story for large flakes.

Compared to other frameworks. Snowfall enforces a directory layout and more defaults; flake-parts stays closer to raw flake outputs. Digga / Hive (divnix) is a separate, largely deprecated collector stack — not the machine mesh concept and not a drop-in substitute for flake-parts.

Examples

Minimal sketch: one system, a default package from pkgs:

{
  description = "Tiny flake-parts example";

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

  outputs = inputs@{ flake-parts, ... }:
    flake-parts.lib.mkFlake { inherit inputs; } {
      imports = [
        # ./modules/dev.nix
        # inputs.someLib.flakeModules.default
      ];
      systems = [ "x86_64-linux" ];
      perSystem = { pkgs, self', ... }: {
        packages.default = pkgs.hello;
        # self'.packages.default is the same derivation for this system
      };
    };
}

Scaffold a new project with the official template: nix flake init -t github:hercules-ci/flake-parts.

References

See also