Host Template System¶
The problem¶
Three hosts, each historically carrying its own near-identical import list and boilerplate. Adding a module meant editing every host; the lists drifted.
The solution¶
A single parameterised template at hosts/templates/desktop.nix, surfaced
through lib/hostTypes.nix as two entry points:
hostTypes.workstation— used by p620 and p510hostTypes.laptop— used by razer
The template takes one argument, profile, and imports the entire module tree.
Profile-specific behaviour is applied with lib.mkIf.
{ profile ? "workstation" }:
{ lib, ... }:
{
imports = [
../../modules/core.nix
../../modules/development.nix
../../modules/desktop.nix
../../modules/virtualization.nix
../../modules/performance.nix
../../modules/email.nix
../../modules/cloud.nix
../../modules/programs.nix
../../modules/common/ai-defaults.nix
../../modules/windows/winboat.nix
];
config = lib.mkMerge [
{
aiDefaults.enable = lib.mkDefault true;
services.openssh.enable = lib.mkDefault true;
}
(lib.mkIf (profile == "laptop") {
services.thermald.enable = lib.mkDefault true;
powerManagement = {
enable = lib.mkDefault true;
cpuFreqGovernor = lib.mkDefault "powersave";
};
})
];
}
How a host wires in¶
lib/hostTypes.nix wraps the template and layers on sensible feature defaults
that a host can still override with mkForce:
workstation = {
imports = [ (desktopTemplate "workstation") ];
config = {
aiDefaults.profile = "workstation";
features = {
development.enable = lib.mkDefault true;
desktop.enable = lib.mkDefault true;
virtualization.enable = lib.mkDefault true;
};
};
};
A host's configuration.nix then imports the host type and declares only what
is unique to it.
Why mkDefault everywhere
The template sets defaults, not hard values. A host that needs something different (e.g. p510 disabling Omarchy's desktop preinstalls to save disk) overrides cleanly without fighting the template.
A server from the same template¶
p510 is the always-on media server, yet it uses the workstation template.
Rather than maintain a separate server template (the old
server/hybrid/base templates were removed), it sets
host.class = "workstation" and overrides only the handful of things that
genuinely differ — currently programs.nixarchy.preinstalls = false and
autologin on.
It was headless until 2026-08-31, when it gained a monitor and the Omarchy
session; the headless-rdp value of host.class remains in the enum but no host
uses it. See p510.
This keeps one template instead of three and avoids the divergence that the template system exists to prevent.
Adding a new host¶
- Create
hosts/<name>/withvariables.nixandhardware-configuration.nix. - Import the appropriate host type (
hostTypes.workstationorhostTypes.laptop). - Declare host-unique bits (GPU profile, monitors, host-specific features).
- Register it in
flake.nix(hostUsers,hardwareProfiles). - Add the host SSH key to
secrets.nixand rekey.
Full procedure: Adding a Host.