Add hosts in two places:
hosts/facts.nixfor shared metadatahosts/<name>/configuration.nixfor repo-local composition
hosts/default.nix is the explicit host loader. It imports hosts/facts.nix and each hosts/<name>/configuration.nix, but it does not recurse into host-local support files.
That means sibling files such as hosts/<name>/hardware-configuration.nix or hosts/<name>/disko.nix are safe to keep next to configuration.nix; they stay private unless that host root imports them.
Repo-local provisioning helpers can live there too. For example, hosts/<name>/bootstrap-pre-kexec.sh is available to the install-host wrapper for source-OS preparation before nixos-anywhere kexecs into the installer.
Create a normalized entry in hosts/facts.nix under aw1cks.hostFacts.
Example darwin host:
{ ... }:
{
aw1cks.hostFacts.my-host = {
system = "aarch64-darwin";
kind = "darwin";
roles = [ "<role>" ];
identity = "personal";
hostName = "my-host";
};
}Example standalone Home Manager host:
{ ... }:
{
aw1cks.hostFacts."alex@laptop" = {
system = "x86_64-linux";
kind = "home-manager";
roles = [ "<role>" ];
identity = "personal";
};
}For standalone Home Manager hosts, the facts key must match the configuration name and follow user@host or user@host.domain.
If enabling services.tailscale-serve or the Darwin services.tailscale-app
module, add tailnetHost to that machine's existing facts entry: its full
Tailscale HTTPS hostname without a scheme, port, or trailing dot (for example
"my-host.example.ts.net"). Import and enable the networking modules explicitly
in host composition, not facts; the AI module does not import them. Both
embedded and standalone Home Manager receive the machine's facts from the
constructors. See networking setup and lifecycle.
Keep these out of facts:
module- embedded
home - local paths
nvidia.pinFile- secrets
Create hosts/<name>/configuration.nix and declare the appropriate configurations.* entry.
Example darwin host:
{ ... }:
{
configurations.darwin.my-host = {
module.system.stateVersion = 6;
home.home.stateVersion = "25.11";
};
}Example standalone Home Manager host:
{ ... }:
{
configurations.home."alex@laptop" = {
module.home.stateVersion = "25.11";
};
}Example NixOS host with embedded Home Manager:
{ ... }:
{
configurations.nixos.workstation = {
module.system.stateVersion = "25.11";
home.home.stateVersion = "25.11";
};
}Keep host declarations minimal.
Constructors already resolve shared values such as:
- system
- username
- home directory
- darwin hostname and host platform defaults
- role-derived profile imports
The current resolution rules come from modules/constructors/*.nix, modules/constructors/_lib.nix, and modules/schema/identity.nix.
These belong in the host composition root instead of facts:
- local file paths
- embedded
homepayloads - NVIDIA enablement and
nvidia.pinFile - host-specific module imports
- host-local
disko.nixandhardware-configuration.niximports - other constructor-specific toggles
Do not manually re-import role-derived profiles in host files unless you intentionally want extra imports beyond the constructor-owned defaults.
Standalone Linux Home Manager hosts can opt into the shared NVIDIA contract:
{ ... }:
{
configurations.home."alex@desktop" = {
nvidia = {
enable = true;
pinFile = ./nvidia.json;
};
module.home.stateVersion = "25.11";
};
}The pin file is JSON and must contain version and sha256 keys.
The updater resolves this host-local path against the consuming flake's Git root, so it must remain inside that flake's source tree.
On non-NixOS Linux, after an NVIDIA pin update, rebuild the Home Manager generation and then run sudo "$(command -v non-nixos-gpu-setup)" to update /run/opengl-driver and EGL platform links.
If the host needs secrets:
- wire them through agenix
- add
age.secrets.*declarations in the relevant module layer - keep encrypted files and secret values out of
hosts/facts.nix
See docs/secret-management.md.
This mostly matters for standalone Home Manager hosts on non-NixOS Linux.
On some domain-joined machines, Nix-built binaries can fail user, group, or host lookups even though the host itself is configured correctly. A common cause is that the host relies on sssd NSS plugins from /etc/nsswitch.conf, while non-NixOS Nix-built glibc binaries often cannot use those host NSS plugins directly.
Installing nscd with the host package manager can work around that by exposing an nscd-compatible socket at /var/run/nscd/socket, which glibc will consult for those lookups.
Treat this as an operational workaround, not a repo contract:
- it can be a practical fix when standalone Home Manager bootstrap or runtime behavior depends on NSS lookups
- upstream SSSD guidance warns about running
nscdalongsidesssdbecause of caching and behavior conflicts - alternatives such as
nsncdmay be a better fit, but they are not yet documented here as a validated standard path
If a downstream environment needs a stronger recommendation than this note, document the validated local approach there rather than promoting an unverified repo-wide rule.
Before relying on flake evaluation, ensure any new Nix files are tracked by git.
Then run the narrowest useful validation for the affected constructor path.
Use nix flake check when it meaningfully covers the change, but do not treat it as a full deployment test. See docs/validation.md.