Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Cross-Platform

NixFleet supports NixOS and macOS from a single API. mkHost detects the platform from the platform parameter and builds the appropriate system type.

Supported platforms

PlatformSystem builderInit systemNotes
x86_64-linuxnixosSystemsystemdFull feature set
aarch64-linuxnixosSystemsystemdFull feature set (ARM servers, edge devices)
aarch64-darwindarwinSystemlaunchdApple Silicon Macs
x86_64-darwindarwinSystemlaunchdIntel Macs

Automatic platform detection

mkHost sets hostSpec.isDarwin based on the platform parameter. You never set it manually. The home option also auto-computes:

  • Linux: /home/<userName>
  • Darwin: /Users/<userName>

What differs by platform

ConcernNixOSDarwin
Core module_nixos.nix - boot, systemd-boot, NetworkManager, polkit, SSH_darwin.nix - system defaults, TouchID sudo, dock management
User configusers.users.<name>.isNormalUserusers.users.<name>.home, .isHidden
Servicessystemd services (systemd.services.*)launchd agents (launchd.agents.*)
ImpermanenceBtrfs root wipe, /persist bind mountsNot applicable
Base scope packagesifconfig, netstat, xdg-utils (system)dockutil, mas (system)
Home ManagerHM NixOS module + impermanence HM moduleHM Darwin module (no impermanence)
Nix daemonManaged by NixOS (nix.gc.automatic, etc.)Determinate-compatible (nix.enable = false)
Trusted users@admin + user (non-server)@admin + user

Platform guards in modules

Use hostSpec.isDarwin (or pkgs.stdenv) for platform-specific logic:

# Using hostSpec (available in all mkHost modules)
{config, lib, ...}: let
  hS = config.hostSpec;
in {
  config = lib.mkIf (!hS.isDarwin) {
    # Linux-only configuration
    services.openssh.enable = true;
  };
}
# Using stdenv (standard Nix pattern)
{lib, pkgs, ...}: {
  home.packages = lib.optionals pkgs.stdenv.isLinux [pkgs.strace]
    ++ lib.optionals pkgs.stdenv.isDarwin [pkgs.darwin.apple_sdk.frameworks.Security];
}

Both approaches work. hostSpec.isDarwin is preferred in NixFleet modules because it is available without pkgs and is consistent with the hostSpec-driven activation pattern.

Scopes and platform support

Not all framework scopes apply to both platforms:

ScopeNixOSDarwin
baseNixOS module + HM moduleDarwin module + HM module
impermanenceNixOS module + HM moduleNot included
nixfleet-agentNixOS service (systemd)Not available
nixfleet-control-planeNixOS service (systemd)Not available

The agent and control-plane services are NixOS-only (systemd). macOS hosts are managed through standard darwin-rebuild and do not participate in fleet orchestration.

Design principle

Prefer simple platform-specific implementations over complex cross-platform abstractions. If a feature only makes sense on one platform, keep it there. The framework handles the platform split at the mkHost level - individual modules should stay focused on their target platform rather than adding conditionals for every difference.

Mixed fleet example

let
  org = {
    userName = "ops";
    timeZone = "UTC";
    sshAuthorizedKeys = ["ssh-ed25519 AAAA..."];
  };
in {
  # NixOS server
  web-01 = mkHost {
    hostName = "web-01";
    platform = "x86_64-linux";
    hostSpec = org;
    modules = [nixfleet-scopes.scopes.roles.server ./hosts/web-01/hardware.nix];
  };

  # macOS developer laptop
  dev-mac = mkHost {
    hostName = "dev-mac";
    platform = "aarch64-darwin";
    hostSpec = org;
    modules = [./hosts/dev-mac/extras.nix];
  };

  # ARM edge device
  sensor-01 = mkHost {
    hostName = "sensor-01";
    platform = "aarch64-linux";
    hostSpec = org;
    modules = [nixfleet-scopes.scopes.roles.endpoint ./hosts/sensor/hardware.nix];
  };
}

All three hosts share org defaults and use the same mkHost call. The framework selects the right system builder, core module, and scope set based on platform.