Skip to content
LogoLogo

mkFlake Usage

mkFlake is purr's standalone flake builder. Use it when you don't need or want flake-parts.

Basic Usage

{
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
    purr.url = "github:nixcafe/purr";
  };
 
  outputs = inputs:
    inputs.purr.lib.mkFlake {
      inherit inputs;
      src = ./.;
      namespace = "myproject";
      outputsBuilder = { pkgs, ... }: {
        formatter = pkgs.nixfmt;
      };
    };
}

Full API Reference

ParameterTypeDefaultDescription
inputsattrsrequiredFlake inputs. Required: nixpkgs. Optional: home-manager (or homeManager) for home-manager support, nix-darwin (or darwin) for darwin support
inputsFornullOr fnidentityTransform { inputs, ... } -> inputs' (or a plain attrset) that filters/replaces the raw flake inputs into the effective inputs purr builds from internally. Modules always keep the raw inputs. See Per-host inputs below
srcpathrequiredProject root directory
namespacenullOr strnullModule option namespace, also used as lib key (lib.<namespace>)
libDirnullOr strnullLib directory (relative to src), auto-detects lib/
flattenLibboolfalseFlatten lib subdirectories into root (no dir nesting)
systemslist["x86_64-linux" "aarch64-linux" "aarch64-darwin"]Systems to generate for
nixpkgsConfigattrs{}nixpkgs config (allowUnfree, etc.)
outputsBuilderfn({ pkgs, system, inputs, namespace, lib, ... }: {})Per-system extra flake outputs. Also receives all extraArgs keys. Results are deep-merged with auto-discovered outputs, so both coexist (e.g. packages from auto-discovery and from outputsBuilder)
modulesDirstr"modules"Module directory name under src
moduleTypesattrs{nixos=["nixos" "shared"]; ...}Subdirectory mapping per output
extraModulesattrs{}{nixos=[...]; darwin=[...]; home=[...]} — raw module injection
extraArgsattrs{}Custom key-value pairs injected into all auto-discovered module args (packages, shells, checks, apps, templates, system specialArgs, home extraSpecialArgs). Purr's own keys override extraArgs on conflict
hostsattrs{}Per-host config: hosts.<name>.meta = { images = [...]; deployable = true; roles.nixpkgs = "..."; ... }, deep-merged over the host's meta.nix. See Host Meta
bundleModulesboolfalseInclude extraModules in the auto-generated default bundle (the default module itself is always generated unless you define your own)
bundleExtraModulesbooltrueInclude extra modules in the default bundle (only when bundleModules = true)
checksDirnullOr strnullauto-detects checks/
shellsDirnullOr strnullauto-detects shells/ then devShells/
overlaysDirnullOr strnullauto-detects overlays/
packagesDirnullOr strnullauto-detects packages/
packagesByNameboolfalseAlso discover packages via by-name/ convention (coexists with regular discovery)
legacyPackagesDirnullOr strnullauto-detects legacyPackages/
legacyPackagesByNameboolfalseAlso discover legacy packages via by-name/ convention (coexists with regular discovery)
appsDirnullOr strnullauto-detects apps/
templatesDirnullOr strnullauto-detects templates/
templatesRecursiveboolfalseWhether to scan templates/ recursively
formatterDirnullOr strnullauto-detects formatters/ then formatter/. The default.nix must return a derivation ({ pkgs, ... }: pkgs.nixfmt-rfc-style)
systemsDirnullOr strnullauto-detects systems/ then hosts/
homesDirnullOr strnullauto-detects homes/
autoInjectbooltrueAuto-inject networking.hostName, home.username, etc.
hydraJobsattrs{}Hydra CI options: { enable, as, dir, systems, include, extra }. See below

Hydra CI (hydraJobs)

Generate a hydraJobs output for Hydra CI that automatically mirrors every buildable output, plus custom jobs from a hydraJobs/ directory:

inputs.purr.lib.mkFlake {
  inherit inputs;
  src = ./.;
  hydraJobs = {
    enable = true;
    systems = ["x86_64-linux"];
    include = [ "checks" "packages" "nixosConfigurations" ];
  };
}

See the hydraJobs page for the full reference.

Customizing Systems

inputs.purr.lib.mkFlake {
  inherit inputs;
  src = ./.;
  systems = [ "x86_64-linux" "aarch64-linux" ];
}

Custom Module Directories

inputs.purr.lib.mkFlake {
  inherit inputs;
  src = ./.;
  moduleTypes = {
    nixos = ["nixos" "shared" "container"];
  };
}

Systems & Homes

inputs.purr.lib.mkFlake {
  inherit inputs;
  src = ./.;
  systemsDir = "systems";   # or "hosts", or null to auto-detect
  homesDir = "homes";
}

Per-host inputs (multi-nixpkgs)

Replace or filter which inputs purr builds with via inputsFor, then point individual hosts at a specific input through a roles meta key. Modules always keep the original inputs argument — replacement only affects how purr builds pkgs, system configs, home configs, and the merged lib. See Host Meta — roles for the full role reference.

# flake.nix
inputs = {
  nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
  nixpkgs-unstable.url = "github:NixOS/nixpkgs/nixos-unstable";
  # ...
};
 
outputs = inputs:
  inputs.purr.lib.mkFlake {
    inherit inputs;
    src = ./.;
    inputsFor = { inputs, ... }: {
      inherit (inputs) nixpkgs;
      inherit (inputs) nixpkgs-unstable;
    };
    hosts.desktop.meta.roles.nixpkgs = "nixpkgs-unstable";
  };
# systems/x86_64-linux/server/meta.nix
{ roles.nixpkgs = "nixpkgs-unstable"; }

Supported role keys: nixpkgs, home-manager, nix-darwin. Homes inherit their linked system's nixpkgs; unmatched homes use the effective-input default.

Formatter

Auto-discover a per-system formatter from formatters/ (or formatter/). The default.nix receives { pkgs, lib, system, namespace, inputs, ... } and must return a derivation:

# formatters/default.nix
{ pkgs, ... }: pkgs.nixfmt-rfc-style

This produces formatter.<system> so nix fmt works out of the box. You can still override via outputsBuilder:

inputs.purr.lib.mkFlake {
  inherit inputs;
  src = ./.;
  outputsBuilder = { pkgs, ... }: {
    formatter = pkgs.alejandra;
  };
}

Legacy Packages

Auto-discover legacyPackages.<system>.* from legacyPackages/ — the convention for unmergeable or non-standard packages, still buildable via nix build .#<name>:

# legacyPackages/hello/default.nix
{ pkgs, ... }: pkgs.hello
inputs.purr.lib.mkFlake {
  inherit inputs;
  src = ./.;
  legacyPackagesByName = true;   # also scan legacyPackages/by-name/<shard>/<name>/package.nix
}

Extra Args

Pass custom values to every auto-discovered module:

inputs.purr.lib.mkFlake {
  inherit inputs;
  src = ./.;
  extraArgs = {
    deploymentTarget = "production";
  };
}

Modules receive extraArgs values as function parameters:

# packages/myapp/default.nix
{ deploymentTarget, pkgs, ... }:
pkgs.writeText "myapp" "target: ${deploymentTarget}"

All auto-discovered modules receive extraArgs keys — packages, shells, checks, apps, templates, system specialArgs, home extraSpecialArgs, and outputsBuilder. Purr's own keys (inputs, pkgs, namespace, lib, etc.) always override extraArgs in case of naming conflicts.