Skip to content

tomwrw/megadots

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

28 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Introduction

My NixOS configuration, built on the dendritic pattern using flake-parts and import-tree. I publish this to help others, as I found other peoples repos extremely helpful when learning Nix/NixOS. Hopefully I can return the favour.

Note: This is my personal config. Any branch other than main should be considered a work in progress. Hardware configs, hostnames, secrets and user attributes are unique to me - you'll need to bring your own.

About

This is the second iteration of my NixOS configuration. The first was a more traditional modular flake structure influenced by Misterio77's nix-config. You can find that version archived here.

This version follows the dendritic pattern - each file is a single feature, flake-parts composes them, and import-tree picks them up automatically. No manual import lists, no inheritance chains. Adding a new feature is one file. Adding a new host is one directory.

The inspiration and structural wiring for this config was from mightyiam's infra config. I learned a ton from their work, and the roots of my config can be directly traced back there.

I'm not a developer. I'm a tinkerer with a consultancy job in a technical field who got curious about declarative system management and fell down the NixOS rabbit hole. This project has genuinely brought some fun back in to computing for me.

Features

  • 🌳 Dendritic pattern flat modules, self-contained inputs, no inheritance chains.
  • 🏷️ Typed host namespace hosts live in configurations.nixos.<host>.module, separate from reusable flake.modules.nixos.* tags.
  • βœ… flake.checks per host nix flake check builds every host closure, so a broken refactor fails fast.
  • 🚫 Strict unfree policy no blanket allowUnfree, every unfree package is enumerated in nixpkgs.config.allowUnfreePackages next to the feature that pulls it in.
  • πŸ“Œ Explicit pkgs-stable a second nixpkgs instance pinned to nixos-25.11, injected via _module.args for anything that wants a stable rather than unstable package.
  • ❄️ NixOS system configuration across multiple hosts.
  • 🏠 Home Manager as a NixOS module for user configuration.
  • πŸ” sops-nix for secrets management with age encryption.
  • ♻️ Impermanence with LUKS encrypted btrfs rollback to a blank root snapshot on every boot.
  • πŸ›‘οΈ Secure Boot via limine with automatic key generation and enrollment.
  • πŸ’Ύ Disko for declarative disk partitioning.
  • ⚑ CachyOS kernel via nix-cachyos-kernel.
  • 🎨 Stylix for consistent theming across the desktop (Home Manager scoped, theme follows the user).
  • πŸš€ nixos-anywhere for bare metal remote deployment.
  • ✨ treefmt + nixfmt nix fmt formats the whole tree; check-flake-file guards against hand-edits to the auto-generated flake.nix.

Hosts

System Description Type CPU GPU
endgame Primary desktop Custom build AMD Ryzen 7800X3D AMD 9070XT
flatmate Mobile workstation Surface Pro 7 Intel i7-1065G7 Intel iGPU
spectre Test VM QEMU/KVM Host passthrough virtio-gpu

All hosts run NixOS unstable with GNOME on Wayland, full disk encryption (LUKS + btrfs), and impermanence. I have a single user (tomwrw) managed through Home Manager.

Structure

.
β”œβ”€β”€ flake.nix                    # Auto-generated by flake-file. Do not edit.
β”œβ”€β”€ justfile                     # Deploy, build and rebuild commands.
β”œβ”€β”€ assets/
β”‚   └── wallpaper/               # Wallpapers used by Stylix.
β”œβ”€β”€ keys/                        # Encrypted age host keys for deployment.
β”œβ”€β”€ secrets/                     # sops-encrypted secrets (per-host + shared).
└── modules/
    β”œβ”€β”€ configurations/
    β”‚   └── nixos.nix            # Host namespace option + flake.checks wiring.
    β”œβ”€β”€ endgame/                 # Per-host: hostname, hardware, disko, imports.
    β”œβ”€β”€ flatmate/
    β”œβ”€β”€ spectre/
    β”œβ”€β”€ home-manager/
    β”‚   β”œβ”€β”€ base.nix             # Baseline HM config for the owner.
    β”‚   └── nixos.nix            # Wires homeManager.<tag> to nixos.<tag>.
    └── *.nix                    # One feature per file, flat. Examples below.

Feature files sit flat under modules/. Each one declares its own flake-file.inputs (if it needs one), then writes into flake.modules.nixos.<tag> or flake.modules.homeManager.<tag> for the scope it belongs to (base, pc, gaming). A few key ones:

  • flake-parts.nix - flake-parts + flake-file + import-tree bootstrap.
  • meta.nix / owner.nix - typed metadata and the owner account.
  • nixpkgs.nix - allowUnfree predicate, pkgs-stable instance.
  • nix-settings.nix - substituters, GC, experimental features, abort-on-warn.
  • impermanence.nix - impermanence module + initrd rollback service.
  • disko.nix / secure-boot.nix / systemd-boot.nix / sops.nix - ecosystem modules.
  • pc.nix / gaming.nix - tag inheritance (e.g. gaming imports pc which imports base).
  • firefox.nix, ghostty.nix, fish.nix, gnome.nix, steam.nix, ... - one feature per file.
  • treefmt.nix - formatter wiring.

flake.nix is auto-generated - run nix run .#write-flake to regenerate it after adding or removing inputs. check-flake-file in nix flake check will fail if the on-disk flake.nix drifts from what the generator would emit.

Usage

Deploying a new host

Deploy a fresh host from the NixOS minimal live CD using nixos-anywhere:

just endgame-deploy

This decrypts the host's age key and LUKS passphrase, then runs nixos-anywhere against the target.

Rebuilding

# Rebuild the current host locally.
just local-rebuild

# Rebuild a remote host.
just endgame-rebuild

Building without switching

just endgame-build

Validating the tree

Before pushing, or after any non-trivial refactor:

# Evaluates every module and builds every host closure.
nix flake check

# Formats every .nix file in place via nixfmt.
nix fmt

Updating flake inputs

nix flake update

Regenerating flake.nix

After adding or removing a module with flake-file.inputs:

nix run .#write-flake

Configuring sops-nix

I use sops-nix for secrets (user passwords, etc). Secrets are encrypted with age using per-host keys. Since I use nixos-anywhere for deployment and impermanence wipes root on every boot, the host's age key needs to exist at deploy time.

My justfile prep recipe handles this - it decrypts the host's age key from keys/<host>.enc and the LUKS passphrase from secrets/<host>.yaml, then passes them to nixos-anywhere via --extra-files and --disk-encryption-keys.

For this to work, you need:

  1. Your age master key at ~/.config/sops/age/keys.txt.
  2. An encrypted host key at keys/<host>.enc.
  3. Host secrets at secrets/<host>.yaml containing a luks-passphrase field.

Community

None of this would be possible without the people who share their work freely. Some shout outs:

About

megadots - a Dendritic NixOS and Home Manager configuration by tomwrw.

Topics

Resources

Stars

Watchers

Forks

Contributors