Architecture
This repository manages two independent NixOS systems through separate flakes. Each system is self-contained with its own flake.nix, inputs, and module tree.
Systems
| Property | Laptop (laptop) | Server (homelab) |
|---|---|---|
| CPU | AMD Ryzen (Radeon iGPU) | Intel |
| Kernel | CachyOS (Chaotic-Nyx) | Vanilla Linux |
| Boot | Lanzaboote (Secure Boot) | systemd-boot |
| Disk | LUKS + ext4 | LUKS + BTRFS + Impermanence |
| Desktop | Sway (Wayland) | Headless |
| Secrets | None | agenix (11 encrypted secrets) |
| Containers | None | 7 active (systemd-nspawn) |
| State Version | 24.11 | 24.11 |
Design Principles
Independent Flakes
The laptop and server configurations are completely decoupled. Each has its own flake.nix with its own set of inputs. This means:
- Updating the server does not affect the laptop, and vice versa.
- Each system can pin different versions of nixpkgs or any other input.
- No shared modules or abstractions that could introduce coupling.
Module Granularity
Every feature is isolated in its own file. The laptop has 22 modules; the server has 16 modules plus 9 container definitions. A module typically owns a single concern:
laptop/modules/
boot.nix # Lanzaboote + Secure Boot
kernel.nix # CachyOS kernel + sysctl
network.nix # iwd WiFi
pipewire.nix # Audio stack
...This makes it trivial to enable, disable, or audit any feature by adding or removing a single import in flake.nix.
Parameterised Configuration
Both flakes pass common values through specialArgs:
specialArgs = {
inherit inputs;
username = "nixos";
hostname = "laptop"; # or "homelab"
domain = "nemnix.site"; # server only
};Modules receive these as function arguments, avoiding hardcoded values:
{ username, hostname, ... }:
{
networking.hostName = hostname;
users.users.${username}.isNormalUser = true;
}Pure Nix, No Channels
Both systems set nix.channel.enable = false and rely entirely on flake inputs. The nixPath is pinned to the flake's nixpkgs input to ensure nix-shell and legacy tooling still work:
nix.nixPath = [ "nixpkgs=${inputs.nixpkgs}" ];Data Flow
flake.nix
├── inputs (nixpkgs, disko, lanzaboote, chaotic, ...)
└── nixosConfigurations.<hostname>
├── specialArgs (username, hostname, domain)
└── modules/
├── hardware-configuration.nix (generated, hardware-specific)
├── disko.nix (declarative disk layout)
├── boot.nix (bootloader config)
├── kernel.nix (kernel, sysctl)
├── network.nix (networking)
└── ... (one file per concern)Flake Inputs
Laptop
| Input | Source | Purpose |
|---|---|---|
nixpkgs | nixos-unstable | Primary package set |
nixpkgs-stable | nixos-25.11 | Stable packages (AppFlowy) |
chaotic | chaotic-cx/nyx | CachyOS kernel, binary cache |
disko | nix-community/disko | Declarative disk partitioning |
lanzaboote | nix-community/lanzaboote v1.0.0 | Secure Boot |
helix | helix-editor/helix master | Editor from git |
neix | Hovirix/neix | Nix package search tool |
Server
| Input | Source | Purpose |
|---|---|---|
nixpkgs | nixos-unstable | Primary package set |
nixpkgs-stable | nixos-25.05 | Stable packages |
disko | nix-community/disko | Declarative disk partitioning |
lanzaboote | nix-community/lanzaboote v0.4.2 | Imported but using systemd-boot |
impermanence | nix-community/impermanence | Ephemeral root filesystem |
agenix | ryantm/agenix | Secrets management |