---
title: Host Configuration Organization
impact: HIGH
impactDescription: Prevents configuration chaos across multiple hosts
tags: hosts,modules,base-config,directory-structure
---


## Why This Matters

Proper host configuration organization prevents duplication, makes maintenance easier, and ensures consistency across multiple machines.

## Directory Structure

```
nixos-config/
├── flake.nix                    # Top-level flake
├── hosts/
│   ├── laptop/
│   │   ├── default.nix          # Host-specific config
│   │   ├── hardware-configuration.nix  # Generated (don't edit)
│   │   └── home.nix             # Home Manager config
│   ├── desktop/
│   │   ├── default.nix
│   │   ├── hardware-configuration.nix
│   │   └── home.nix
│   └── base.nix                 # Shared by all hosts (optional)
├── modules/                     # Reusable NixOS modules
├── overlays/                    # Custom overlays
├── home-manager/                # Shared Home Manager configs
│   ├── shell/
│   ├── applications/
│   └── common.nix
└── secrets/                     # Age-encrypted secrets
```

## Host Configuration Pattern

### Incorrect: Everything in one file

```nix
# hosts/laptop/default.nix
{ config, pkgs, ... }:
{
  # Hardware config (copied from hardware-configuration.nix)
  boot.initrd.availableKernelModules = [ "xhci_pci" "nvme" "usb_storage" ];
  # ... 50 lines of hardware config ...

  # Network config
  networking.hostName = "laptop";
  networking.networkmanager.enable = true;

  # User config
  users.users.john = {
    isNormalUser = true;
    extraGroups = [ "wheel" "networkmanager" ];
  };

  # Packages
  environment.systemPackages = with pkgs; [ vim git wget ];

  # Services
  services.openssh.enable = true;

  # Home Manager
  imports = [
    ./home.nix  # Or inline the entire home config
  ];
}
```

**Problems:**
- Hardware config duplicated (should import hardware-configuration.nix)
- User config duplicated across hosts
- No shared configuration
- Hard to maintain

### Correct: Modular structure

```nix
# hosts/laptop/default.nix
{ inputs, pkgs, pkgs-stable, system, ... }:
{
  imports = [
    ./hardware-configuration.nix  # Import hardware config
    ../base.nix                  # Import shared config
    inputs.home-manager.nixosModules.home-manager
    {
      home-manager.useGlobalPkgs = true;
      home-manager.useUserPackages = true;
      home-manager.users.john = import ./home.nix;
      home-manager.extraSpecialArgs = {
        inherit inputs pkgs-stable system;
      };
      nixpkgs.overlays = [ inputs.some-overlay.overlays.default ];
    }
  ];

  # Host-specific config only
  networking.hostName = "laptop";
}
```

## Shared Base Configuration

```nix
# hosts/base.nix
{ config, pkgs, inputs, ... }:
{
  # Network
  networking.networkmanager.enable = true;

  # Time and locale
  time.timeZone = "America/New_York";
  i18n.defaultLocale = "en_US.UTF-8";

  # Users (shared across all hosts)
  users.users.john = {
    isNormalUser = true;
    extraGroups = [ "wheel" "networkmanager" ];
  };

  # Common packages
  environment.systemPackages = with pkgs; [
    vim
    git
    wget
    tmux
  ];

  # Common services
  services.openssh.enable = true;

  # Nix settings
  nix.settings.experimental-features = [ "nix-command" "flakes" ];
}
```

## Hardware Configuration

```nix
# hosts/laptop/default.nix
{ ... }:
{
  imports = [
    ./hardware-configuration.nix  # Generated by nixos-generate-config
    ../base.nix
    # ...
  ];

  networking.hostName = "laptop";
}
```

**Important:** Don't edit `hardware-configuration.nix` manually. It's generated by `nixos-generate-config` and should be replaced when hardware changes.

## Home Manager Configuration

### Host-specific home.nix

```nix
# hosts/laptop/home.nix
{ config, pkgs, inputs, ... }:
{
  imports = [
    ../../home-manager/shell
    ../../home-manager/applications
    ../../home-manager/common.nix
  ];

  # Host-specific user config
  home.packages = with pkgs; [
    laptop-specific-package
  ];
}
```

### Shared Home Manager configs

```nix
# home-manager/shell/default.nix
{ config, pkgs, ... }:
{
  imports = [
    ./fish
    ./neovim
    ./git
  ];
}

# home-manager/common.nix
{ config, pkgs, ... }:
{
  home.packages = with pkgs; [
    jq
    ripgrep
    fzf
  ];

  programs.git.enable = true;
  programs.git.userName = "John Doe";
  programs.git.userEmail = "john@example.com";
}
```

## Multiple Hosts Example

```nix
# flake.nix
outputs = { self, nixpkgs, home-manager, ... }@inputs: {
  nixosConfigurations.laptop = nixpkgs.lib.nixosSystem {
    specialArgs = { inherit inputs; };
    modules = [ ./hosts/laptop ];
  };

  nixosConfigurations.desktop = nixpkgs.lib.nixosSystem {
    specialArgs = { inherit inputs; };
    modules = [ ./hosts/desktop ];
  };

  nixosConfigurations.server = nixpkgs.lib.nixosSystem {
    specialArgs = { inherit inputs; };
    modules = [ ./hosts/server ];
  };
};
```

Each host uses the same `base.nix` but can override settings:

```nix
# hosts/server/default.nix
{ ... }:
{
  imports = [ ../base.nix ./hardware-configuration.nix ];

  # Override time zone for server
  time.timeZone = "UTC";

  # Add server-specific packages
  environment.systemPackages = with pkgs; [
    htop
    iotop
  ];
}
```

## Module Pattern

For reusable functionality, create modules:

```nix
# modules/docker.nix
{ config, pkgs, ... }:
{
  virtualisation.docker = {
    enable = true;
    enableOnBoot = true;
  };

  users.users.john.extraGroups = [ "docker" ];
}
```

Use in host config:

```nix
# hosts/laptop/default.nix
{ ... }:
{
  imports = [
    ../base.nix
    ../../modules/docker  # Import module
    ./hardware-configuration.nix
  ];
}
```

## Common Mistakes

1. **Editing hardware-configuration.nix**: Changes are lost when regenerating. Put host-specific config in `default.nix` instead.

2. **Duplicating config across hosts**: Use `base.nix` or modules for shared configuration.

3. **Not separating host-specific and user-specific**: Keep host config in `hosts/*/default.nix`, user config in `home.nix` or `home-manager/`.

4. **Mixing concerns**: Don't put shell config in system packages. Use Home Manager for user-level packages.

## Quick Checklist

- [ ] Each host imports hardware-configuration.nix
- [ ] Shared config in base.nix or modules
- [ ] Home Manager configured in host file
- [ ] Host-specific settings only in host's default.nix
- [ ] User config in home.nix or home-manager/
- [ ] No duplication of hardware config
- [ ] No duplication of user config
