Skip to content

Lesson 05 — Wimpy's Config Tour

Source: vendor/nix-config-main/github.com/wimpysworld/nix-config (682 ★)
Who: Wimpy (@wimpysworld) — co-host of Linux Matters podcast
Featured on: Linux Matters Episode 7 — "Immutable Desktop Linux for Anyone"
Scale: 17 machines — desktops, laptops, servers, VMs, macOS
Channel: nixos-26.05 stable

Why Study This?

This is the deep end. Wimpy's config demonstrates patterns that only make sense at scale — when you have many machines and can't manage each one individually. Understanding this shows where Nix's real power lives.

Don't try to replicate this immediately. Study it to understand the destination.

The Core Insight: Broadcast-and-Gate

Traditional NixOS configs use selective imports — each host file lists exactly which modules it wants:

# Typical approach: host manually selects modules
modules = [
  ./modules/desktop.nix
  ./modules/gpu-amd.nix
  ./modules/laptop.nix
];

Wimpy's approach inverts this. Every module is imported by every host. Each module checks host metadata and decides whether to activate:

# Wimpy's approach: module activates itself based on host properties
{ config, lib, ... }:
lib.mkIf config.noughty.host.is.workstation {
  boot.plymouth.enable = true;
}

A module whose condition is false evaluates to nothing — zero cost in Nix because evaluation is lazy.

This pattern is called broadcast-and-gate.

Why this is powerful

Adding a new feature: Drop a new directory with a self-gating module. No other files to touch. Every matching host picks it up automatically.

Adding a new host: Add a registry entry in a TOML file + hardware config. The new host automatically gets the right desktop, drivers, services — because modules gate on properties, not host names.

The noughty Module System

vendor/nix-config-main/lib/noughty/ is Wimpy's custom layer that makes broadcast-and-gate work cleanly.

Every host is registered in lib/registry-systems.toml with its properties:

[skrye]
kind = "workstation"
platform = "x86_64-linux"
formFactor = "desktop"
gpu = ["amd"]
username = "martin"
desktop = "hyprland"

The noughty module system reads this and creates NixOS options under config.noughty.*:

config.noughty.host.is.workstation  # → true
config.noughty.host.is.laptop       # → false
config.noughty.host.gpu.hasAmd      # → true
config.noughty.host.gpu.hasNvidia   # → false

Modules use these booleans with lib.mkIf to gate their config. Type-safe, documented, derived automatically.

Top-Level Structure

nix-config-main/
├── flake.nix               ← entry point (much more complex than Ian's)
├── lib/
│   ├── noughty/            ← the module system (registry → NixOS options)
│   ├── flake-builders.nix  ← generates all configs from registry TOML
│   ├── registry-systems.toml
│   └── registry-users.toml
├── common/                 ← shared between NixOS and nix-darwin
├── nixos/
│   ├── _mixins/            ← self-gating modules (the broadcast part)
│   │   ├── console/
│   │   ├── desktop/
│   │   │   ├── hyprland/
│   │   │   └── wayfire/
│   │   ├── hardware/
│   │   ├── network/
│   │   ├── scripts/
│   │   └── ...
│   ├── skrye/              ← host-specific: ONLY hardware (disks, kernel)
│   ├── bane/
│   └── ...
├── home-manager/
│   └── _mixins/            ← same pattern for user-level
│       ├── desktop/
│       ├── terminal/
│       ├── development/
│       └── users/
├── darwin/                 ← macOS-specific modules
├── overlays/               ← custom package modifications
├── pkgs/                   ← custom packages
└── justfile                ← convenience commands (like make, but better)

The _mixins Convention

Directories named _mixins (underscore prefix = "internal") contain the self-gating modules. The underscore is a convention to indicate these are building blocks, not host configs.

Each mixin is a directory with default.nix as the entry point. They're kept small and single-concern.

Key Advanced Concepts

1. Disko — Declarative Disk Layouts

Ian has a hand-generated hardware-configuration.nix for his one machine. Wimpy uses Disko to declare disk layouts in Nix:

# Disk partitioning declared in Nix, applied once during install
disko.devices.disk.main = {
  type = "disk";
  device = "/dev/nvme0n1";
  content.type = "gpt";
  content.partitions = { ... };
};

This means the install process is fully automated — Disko formats disks, then nixos-install puts the OS on them. The install-system script handles everything.

2. SOPS — Encrypted Secrets

Secrets (SSH keys, API tokens, passwords) need to live somewhere. Wimpy uses sops-nix:

  • secrets/secrets.yaml is encrypted with age keys
  • Each host has an age key in /var/lib/private/sops/age/keys.txt
  • Secrets are decrypted at activation time and placed where modules expect them

For a single machine, this is overkill. At 17 machines it's essential.

3. FlakeHub Cache

Every push to main triggers CI that builds all configurations and publishes them to FlakeHub Cache. This means just apply pulls pre-built binaries rather than rebuilding locally.

Equivalent of a private binary cache for your personal configs — zero compile time on apply.

4. The justfile

Rather than remembering long nixos-rebuild incantations, Wimpy uses just:

just host      # build and switch NixOS config
just home      # build and switch Home Manager config
just update    # update all flake inputs
just iso       # build a bootable ISO

This is a good habit regardless of config complexity. Document your common commands.

5. Overlays

overlays/
├── localPackages.nix    ← adds pkgs from ./pkgs/ to nixpkgs
├── modifiedPackages.nix ← patches or overrides existing nixpkgs packages
└── unstablePackages.nix ← makes pkgs.unstable available in all modules

Overlays let you modify the pkgs attribute set that all modules receive. Applied in order: local → modified → unstable.

What to Learn FROM This (Not TO Replicate)

For a single machine, you don't need: - The noughty module system - Registry TOML files - The broadcast-and-gate pattern - Disko (though it's worth knowing) - FlakeHub Cache

But you should understand: - Why these patterns exist (scale, maintainability) - The _mixins directory convention (keep modules small and single-concern) - Using justfile for common operations - The concept of secrets management (you'll need it eventually) - Overlays for customizing nixpkgs

Wimpy's Machines (Star Wars Theme)

Workstations and servers are Sith Lords (skrye, sidious, bane, malak...).
VMs are TIE fighters (crawler, dagger, fighter, defender).
Dual-boot: NixOS gets the Sith name, the other OS gets their public persona.

Naming your machines consistently is a minor thing but makes configs much more readable.