Skip to content

Platform batteries

Each platform is a kind you declare, with a sink that collects its modules. A battery turns the sink into the flake output. The builders and pkgs are roles that read the scope, so each machine can use its own channel. This fleet has a NixOS host with a guest, a mac, a phone and a standalone home:

modules/fleet.nix
# Four kinds of machine and standalone homes. Each kind's sink builds its output with a battery.
{
yen,
inputs,
...
}:
let
b = yen.lib.batteries;
pkgsOf = s: inputs.nixpkgs.legacyPackages.${s.system};
machine = {
spawns.user = yen.lib.pointing "on" yen.user;
};
in
{
yen.kinds.fleet = {
spawns = {
host = _: yen.host;
mac = _: yen.mac;
phone = _: yen.phone;
home = _: yen.home;
};
sinks.out.reduce = yen.lib.reduce.merge;
};
yen.kinds.host = machine // {
fields.system = yen.lib.str;
spawns = machine.spawns // {
guest = yen.lib.pointing "on" yen.guest;
};
sinks.nixos.out = b.nixos.system {
# (1)
from = yen.kinds.host.sinks.nixos;
inherit (inputs) nixpkgs;
};
sinks.os.nixos = b.imports { from = yen.kinds.host.sinks.os; }; # (2) a user's home (os) into NixOS
};
yen.kinds.guest = {
fields = {
on = yen.kinds.host;
system = yen.lib.str;
};
# a guest's NixOS goes into its host as microvm.vms.<guest>
sinks.nixos.nixos = b.microvm.guest {
# (3)
from = yen.kinds.guest.sinks.nixos;
pkgs = pkgsOf;
};
};
yen.kinds.mac = machine // {
fields.system = yen.lib.str;
sinks.darwin.out = b.darwin.system {
# (4)
from = yen.kinds.mac.sinks.darwin;
darwinSystem = _: inputs.nix-darwin.lib.darwinSystem;
system = m: m.system;
};
sinks.os.darwin = b.imports { from = yen.kinds.mac.sinks.os; };
};
yen.kinds.phone = {
fields.system = yen.lib.str;
sinks.droid.out = b.droid.system {
# (5)
from = yen.kinds.phone.sinks.droid;
inherit (inputs.nix-on-droid.lib) nixOnDroidConfiguration;
# nix-on-droid pins its own nixpkgs: newer nixpkgs dropped lib.mdDoc, which it still uses
pkgs = s: import inputs.nix-on-droid.inputs.nixpkgs { inherit (s) system; };
};
sinks.homeManager.droid = b.droid.home { from = yen.kinds.phone.sinks.homeManager; }; # (6)
};
yen.kinds.home = {
fields = {
user = yen.kinds.user;
system = yen.lib.str;
};
sinks.homeManager.out = b.home-manager.system {
# (7)
from = yen.kinds.home.sinks.homeManager;
homeManagerConfiguration = _: inputs.home-manager.lib.homeManagerConfiguration;
pkgs = pkgsOf;
};
};
yen.kinds.user = {
fields.on = yen.lib.listOf (
yen.lib.oneOf [
yen.kinds.host
yen.kinds.mac
]
);
# a user's home goes into the machine it is on
sinks.homeManager.os = b.home-manager.into-host { from = yen.kinds.user.sinks.homeManager; }; # (8)
};
yen.fleet.main = { };
yen.flake = { out, ... }: out;
}
  • (1) builds nixosConfigurations.<name> from the nixos sink of a host.
  • (2) turns a sink of modules into one module. A user’s home goes into the NixOS host this way.
  • (3) is a guest. Its NixOS config goes into its host as microvm.vms.<guest>.
  • (4) builds darwinConfigurations.<name>.
  • (5) builds nixOnDroidConfigurations.<name>, and (6) gives the phone’s home-manager config to it.
  • (7) builds homeConfigurations.<name> for a standalone home.
  • (8) gives a user’s home to the machine the user is on, as home-manager.users.<user>.imports.

The machines, and the aspects that give them their configuration:

modules/machines.nix
# One of each: a NixOS host with a guest, a mac, a phone, and a standalone home. ana is on the host and the mac.
{ yen, inputs, ... }:
let
nixos = yen.lib.batteries.nixos;
darwin = yen.lib.batteries.darwin;
in
{
yen.host.server.system = "x86_64-linux";
yen.guest.ci = {
on = yen.host.server;
system = "x86_64-linux";
};
yen.mac.studio.system = "aarch64-darwin";
yen.phone.pixel.system = "aarch64-linux";
yen.user.ana.on = [
yen.host.server
yen.mac.studio
];
yen.home.ana-laptop = {
user = yen.user.ana;
system = "x86_64-linux";
};
yen.aspects.server = {
at = yen.host.server;
nixos = {
imports = [
(yen.lib.batteries.home-manager.module inputs.home-manager.nixosModules.home-manager) # (1) useGlobalPkgs too
inputs.microvm.nixosModules.host
];
boot.loader.grub.device = "nodev";
fileSystems."/" = {
device = "/dev/sda1";
fsType = "ext4";
};
nixpkgs.hostPlatform = "x86_64-linux";
system.stateVersion = "25.05";
};
};
yen.aspects.hostname = {
at = [
yen.kinds.host
yen.kinds.guest
];
nixos = nixos.hostname;
};
yen.aspects.guest = {
at = yen.kinds.guest;
nixos = {
imports = [ inputs.microvm.nixosModules.microvm ];
system.stateVersion = "25.05";
};
};
yen.aspects.studio = {
at = yen.mac.studio;
darwin = {
imports = [ inputs.home-manager.darwinModules.home-manager ];
system.stateVersion = 6;
};
};
yen.aspects.mac-owner = {
at = yen.mac.studio;
darwin = darwin.primary-user { user = _: "ana"; }; # (2)
};
yen.aspects.brew = {
at = yen.mac.studio;
brew.casks = [ "firefox" ];
};
yen.kinds.mac.sinks.brew.darwin = darwin.homebrew { from = yen.kinds.mac.sinks.brew; }; # (3)
yen.aspects.pixel = {
at = yen.phone.pixel;
droid.system.stateVersion = "24.05";
homeManager = {
home.stateVersion = "24.05";
programs.git.enable = true;
};
};
# ana's accounts: a user has no nixos or darwin sink, so these go up to each machine she is on
yen.aspects.accounts = {
at = yen.kinds.user;
nixos = nixos.define-user;
darwin =
{ scope, ... }:
{
users.users.${scope.name}.home = "/Users/${scope.name}";
};
};
# ana's home: inside the host and the mac, and standalone on her laptop
yen.aspects.ana-home = {
at = [
yen.user.ana
yen.home.ana-laptop
];
homeManager = {
home.stateVersion = "25.05";
programs.git.enable = true;
};
};
yen.aspects.standalone = {
at = yen.kinds.home;
homeManager =
{ home, ... }:
{
home.username = home.user.name;
home.homeDirectory = "/home/${home.user.name}";
};
};
}

(1) is a battery too: it gives the NixOS host home-manager with the machine’s pkgs. (2) sets system.primaryUser on the mac. (3) installs homebrew casks, brews and masApps from a sink.

Battery Value of Gives
configurations { from; output; build; } out of any module sink <output>.<scope name> = build scope modules
nixos.system { from; nixpkgs; } out of the NixOS sink nixosConfigurations.<name>
darwin.system { from; darwinSystem; system; } out of the darwin sink darwinConfigurations.<name>
darwin.primary-user { user ? ; }, darwin.homebrew { from; } darwin keys system.primaryUser; homebrew from a sink of casks, brews, masApps
home-manager.system { from; homeManagerConfiguration; pkgs; } out of a home’s sink homeConfigurations.<name>
home-manager.into-host { from; } a user sink’s key that gives to the machine home-manager.users.<user>.imports
home-manager.module module a machine key home-manager with the machine’s pkgs
droid.system { from; nixOnDroidConfiguration; pkgs; }, droid.home { from; } phone sinks nixOnDroidConfigurations.<name>, its home-manager config
microvm.guest { from; pkgs; } a guest sink’s key that gives to the host microvm.vms.<guest> of the host
imports { from; } a sink’s key the sink’s modules as one module

configurations is the generic battery behind the platform builders. See Generic batteries.

ContributeCommunitySponsor