Skip to content

Host Configuration

Hosts are where modules come together. A host configuration selects which nixosModules make up the system, defines users, and assigns homeManagerModules to each user.

Host Directory Structure

Each host lives under modules/hosts/<hostname>/:

modules/hosts/cyril-nixos/
├── configuration.nix               # System: module composition + nixosConfiguration
├── user-cyril.nix                  # User: system user + Home Manager modules
└── _hardware-configuration.nix     # Hardware: auto-generated by nixos-generate-config

System Configuration

The configuration.nix file creates a nixosConfiguration by composing modules:

nix
# modules/hosts/cyril-nixos/configuration.nix
{ inputs, self, ... }:
{
  flake.nixosConfigurations.cyril-nixos = inputs.nixpkgs.lib.nixosSystem {
    specialArgs = { inherit inputs self; };
    modules = [
      ./_hardware-configuration.nix

      # System
      self.nixosModules.base-system
      self.nixosModules.ssh-server
      self.nixosModules.tailscale
      self.nixosModules.bluetooth
      self.nixosModules.virtualisation
      self.nixosModules.fonts
      self.nixosModules.nh
      self.nixosModules.kmscon

      # Services
      self.nixosModules.audio
      self.nixosModules.printing
      self.nixosModules.flatpak

      # Boot
      self.nixosModules.grub

      # Desktop
      self.nixosModules.nvidia
      self.nixosModules.base-videoDrivers
      self.nixosModules.xserver
      self.nixosModules.xkb
      self.nixosModules.hyprland
      self.nixosModules.plasma
      self.nixosModules.ly

      # Packages
      self.nixosModules.packages-global
      self.nixosModules.packages-cyril-nixos

      # Theming
      self.nixosModules.stylix

      # Home Manager
      self.nixosModules.home-manager
      self.nixosModules.cyril-nixos-user-cyril

      # Inline overrides
      {
        networking.hostName = "cyril-nixos";
      }
    ];
  };
}

Key points:

  • specialArgs = { inherit inputs self; } — this is what makes inputs and self available inside all modules. Without this, modules can't reference external flake inputs or other modules.
  • self.nixosModules.<name> — references modules registered by other files under modules/.
  • Inline attribute sets — you can mix in one-off settings (like networking.hostName) directly in the modules list.
  • _hardware-configuration.nix — prefixed with _ by convention; auto-generated by nixos-generate-config.

User Configuration

Each user gets a file that defines the system user and wires up Home Manager modules:

nix
# modules/hosts/cyril-nixos/user-cyril.nix
{ ... }:
{
  flake.nixosModules.cyril-nixos-user-cyril =
    { pkgs, self, inputs, ... }:
    {
      # System user definition
      users.users.cyril = {
        isNormalUser = true;
        extraGroups = [ "wheel" "wireguard" ];
        openssh.authorizedKeys.keys = [
          "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5..."
        ];
        shell = pkgs.zsh;
      };

      # Home Manager module composition
      home-manager.users.cyril.imports = [
        # Base
        self.homeManagerModules.home

        # CLI
        self.homeManagerModules.zsh
        self.homeManagerModules.ssh-agent
        self.homeManagerModules.oh-my-posh
        self.homeManagerModules.fzf
        self.homeManagerModules.zoxide
        self.homeManagerModules.atuin
        self.homeManagerModules.fastfetch
        self.homeManagerModules.tmux
        self.homeManagerModules.carapace

        # Desktop
        self.homeManagerModules.dunst
        self.homeManagerModules.flameshot
        self.homeManagerModules.hypr
        self.homeManagerModules.rofi
        self.homeManagerModules.waybar
        self.homeManagerModules.stylix-hm

        # Programs
        self.homeManagerModules.spicetify
        self.homeManagerModules.foot
        self.homeManagerModules.kitty

        # Packages
        self.homeManagerModules.packages-global
        self.homeManagerModules.packages-cyril-nixos

        # External modules
        inputs.spicetify-nix.homeManagerModules.default
      ];
    };
}

Notice that the user config file is itself a flake.nixosModules (not a homeManagerModules). It's a NixOS module because it defines users.users.* and home-manager.users.*, which are NixOS-level options. The Home Manager modules are imported inside the home-manager.users.<name>.imports list.

The home-manager Module

For Home Manager integration to work, the host must include a module that sets up the Home Manager NixOS integration:

nix
# modules/nixosModules/config/home-manager.nix
{ ... }:
{
  flake.nixosModules.home-manager =
    { inputs, self, ... }:
    {
      imports = [ inputs.home-manager.nixosModules.home-manager ];

      home-manager = {
        useGlobalPkgs = true;
        useUserPackages = true;
        extraSpecialArgs = { inherit inputs self; };
      };
    };
}

This is included once in the host's configuration.nix and enables home-manager.users.* for all user definitions.

WARNING

Always include self.nixosModules.home-manager in your host's module list before any user modules. Without it, home-manager.users.* options won't exist.

Adding a New Host

1. Create the host directory

bash
mkdir -p modules/hosts/my-host

2. Generate hardware configuration

Boot the target machine (or use a live ISO) and run:

bash
nixos-generate-config --root /mnt --show-hardware-config > modules/hosts/my-host/_hardware-configuration.nix

3. Create the system configuration

nix
# modules/hosts/my-host/configuration.nix
{ inputs, self, ... }:
{
  flake.nixosConfigurations.my-host = inputs.nixpkgs.lib.nixosSystem {
    specialArgs = { inherit inputs self; };
    modules = [
      ./_hardware-configuration.nix
      self.nixosModules.base-system
      self.nixosModules.grub
      self.nixosModules.audio
      self.nixosModules.packages-global
      self.nixosModules.home-manager
      self.nixosModules.my-host-user-alice
      { networking.hostName = "my-host"; }
    ];
  };
}

4. Create a user configuration

nix
# modules/hosts/my-host/user-alice.nix
{ ... }:
{
  flake.nixosModules.my-host-user-alice =
    { pkgs, self, ... }:
    {
      users.users.alice = {
        isNormalUser = true;
        extraGroups = [ "wheel" ];
        shell = pkgs.zsh;
      };

      home-manager.users.alice.imports = [
        self.homeManagerModules.home
        self.homeManagerModules.zsh
        self.homeManagerModules.packages-global
      ];
    };
}

5. Build

bash
sudo nixos-rebuild switch --flake .#my-host

Multiple Hosts, Shared Modules

The power of this architecture is that modules are shared across hosts. A module like tailscale is defined once and included in any host that needs it:

cyril-nixos/configuration.nix  →  self.nixosModules.tailscale  ✓
wsl/configuration.nix          →  (not included)
my-server/configuration.nix    →  self.nixosModules.tailscale  ✓

Similarly, users on different hosts can share the same Home Manager modules while having different selections:

cyril on cyril-nixos  →  zsh, tmux, hypr, waybar, kitty, ...
cyril on wsl          →  zsh, tmux (no GUI modules)