Skip to content

Builder Functions

Ghaf provides reusable builder functions that can be consumed by both Ghaf internally and downstream projects. This eliminates code duplication and ensures consistency across projects.

Ghaf now exports builder functions via flake.builders that can be imported and used by any downstream project.

Creates a Ghaf configuration for supported target profiles such as laptop-x86 and orin.

# Function signature
mkGhafConfiguration :: {
self: flake,
inputs: attrSet,
lib: lib,
} -> ({
name: string,
system: string,
profile: string,
hardwareModule: module,
variant?: string,
extraModules?: [module],
extraConfig?: attrSet,
vmConfig?: attrSet
} -> {
hostConfiguration: nixosSystem,
variant: string,
name: string,
package: derivation
})

Creates a bootable ISO installer for a Ghaf image package. The outer builder application evaluates the shared installer NixOS system once, and per-target calls only override the ISO contents with the target-specific Ghaf image.

# Function signature
mkGhafInstaller :: {
self: flake,
lib: lib,
system?: string = "x86_64-linux"
extraModules?: [module]
} -> ({
name: string,
imagePath: path
} -> {
name: string,
package: derivation
})
{
inputs = {
ghaf.url = "github:tiiuae/ghaf";
nixpkgs.follows = "ghaf/nixpkgs";
};
outputs = { ghaf, nixpkgs, ... }:
let
mkGhafConfiguration = ghaf.builders.mkGhafConfiguration {
self = ghaf;
inputs = { inherit ghaf nixpkgs; };
lib = ghaf.lib;
};
myLaptop = mkGhafConfiguration {
name = "my-laptop";
system = "x86_64-linux";
profile = "laptop-x86";
hardwareModule = ./hardware-configuration.nix;
variant = "debug";
extraModules = [
ghaf.nixosModules.reference-profiles
ghaf.nixosModules.profiles
];
extraConfig = {
reference.profiles.mvp-user-trial.enable = true;
};
};
in {
nixosConfigurations.${myLaptop.name} = myLaptop.hostConfiguration;
packages.x86_64-linux.${myLaptop.name} = myLaptop.package;
};
}
{
outputs = { ghaf, nixpkgs, ... }:
let
system = "x86_64-linux";
mkGhafConfiguration = ghaf.builders.mkGhafConfiguration {
self = ghaf;
inputs = { inherit ghaf nixpkgs; };
lib = ghaf.lib;
};
mkGhafInstaller = ghaf.builders.mkGhafInstaller {
self = ghaf;
lib = ghaf.lib;
inherit system;
extraModules = [
{
networking.wireless.networks."MyWiFi".psk = "password";
}
];
};
laptop = mkGhafConfiguration {
name = "my-laptop";
inherit system;
profile = "laptop-x86";
hardwareModule = ./hardware-configuration.nix;
variant = "debug";
};
installer = mkGhafInstaller {
name = laptop.name;
imagePath = laptop.package;
};
in {
packages.${system} = {
${laptop.name} = laptop.package;
${installer.name} = installer.package;
};
};
}

The builders are located in lib/builders/ and are exported via flake.builders. They are also available as self.builders within the flake, allowing direct usage in flake-modules without intermediate files.

Internal flake-modules call builders with parameters to get the builder functions:

targets/laptop/flake-module.nix
{
lib,
self,
inputs,
...
}:
let
system = "x86_64-linux";
# Call builders with parameters to get the builder functions
ghaf-configuration = self.builders.mkGhafConfiguration {
inherit self inputs;
inherit (self) lib;
};
ghaf-installer = self.builders.mkGhafInstaller {
inherit self system;
inherit (self) lib;
extraModules = installerModules;
};
# Then use the builder functions with machine-specific parameters
target-configs = [
(ghaf-configuration {
name = "lenovo-x1-carbon-gen11";
inherit system;
profile = "laptop-x86";
hardwareModule = self.nixosModules.hardware-lenovo-x1-carbon-gen11;
variant = "debug";
extraModules = commonModules;
extraConfig = {
reference.profiles.mvp-user-trial.enable = true;
};
})
];
target-installers = map (t: ghaf-installer {
name = t.name;
imagePath = self.packages.${system}.${t.name};
}) target-configs;
in {
flake.packages.${system} = builtins.listToAttrs (
map (t: lib.nameValuePair t.name t.package) (target-configs ++ target-installers)
);
}

External projects access builders via the flake output:

{
inputs.ghaf.url = "github:tiiuae/ghaf";
outputs = { ghaf, nixpkgs, ... }: let
mkGhafConfiguration = ghaf.builders.mkGhafConfiguration {
self = ghaf;
inputs = { inherit ghaf nixpkgs; };
lib = ghaf.lib;
};
in {
# Use the builder...
};
}

This approach eliminates relative import paths (../../lib/builders/) while maintaining clean separation between internal and external usage patterns.