Moved to Codeberg.
The flake follows the dendritic pattern: every .nix file under modules/ is a
flake-parts module, all of them imported automatically by
import-tree. No file lists the others, so adding a
module is just adding a file.
There is one file per feature, and each one publishes itself as an aspect named after the
file: modules/system/ssh.nix defines flake.modules.nixos.ssh, modules/apps/vlc.nix
defines flake.modules.homeManager.vlc. A feature that needs both a system and a user side
configures both in the same file, under the same aspect name in each class:
modules/hardware/bluetooth.nix turns on hardware.bluetooth for the system and
services.blueman-applet for the user, and modules/desktop/hyprland.nix holds both the
programs.hyprland and the wayland.windowManager.hyprland side of the window manager.
There are no profile aspects — no base, no desktop bundle. Every host lists every aspect it
wants, so modules/hosts/<host>.nix is the complete inventory of that machine.
Features are grouped into directories by what they do, not by which module class they configure:
| Path | Holds |
|---|---|
modules/system/ |
OS plumbing: bootloader, kernel, locale, nix settings and GC, SSH, GnuPG, NetworkManager, virtualisation |
modules/hardware/ |
device enablement: GPU, graphics, input devices, Bluetooth, Android, audio, USB |
modules/desktop/ |
the Hyprland session and its furniture: WM, lock/idle/wallpaper, bar, launcher, notifications, greeter, portals, screenshots, media and backlight keys, and theming |
modules/apps/ |
end-user applications: browser, terminal, file browser, media players, chat, Steam, Flatpak |
modules/cli/ |
terminal environment and tooling: shell, prompt, tmux, Neovim, Git, and CLI utilities |
A directory is organisation only: the aspect a file publishes is decided by its contents, so
modules/hardware/bluetooth.nix contributes to both classes while modules/system/ssh.nix
contributes to nixos alone. Features large enough to want their own directory get one and are
named after it (modules/desktop/waybar/ → homeManager.waybar, modules/cli/nixvim/ →
homeManager.nixvim, whose plugin files all contribute to that one aspect).
The rest of the tree is not features:
| Path | Holds |
|---|---|
modules/users/<user>.nix |
flake.modules.nixos.<user> (the system account) and flake.modules.homeManager.<user> (identity: username, home directory, Git identity) |
modules/hosts/<host>.nix |
everything about one machine: its flake.modules.nixos.<host> and flake.modules.homeManager.<host> aspects, listing the aspects it imports plus its host-specific settings, and the nixosConfigurations.<host> and homeConfigurations."<user>@<host>" outputs built from them |
modules/flake/*.nix |
the flake itself: nixpkgs settings, and the flake modules declaring flake.modules and flake.homeConfigurations |
modules/home-manager.nix |
Home Manager managing itself, and home.stateVersion |
Modules are enabled by being imported, not by an option: adding a feature means writing the file
and adding its name to the imports of every host that should have it. Third-party modules
(Stylix, nixvim, nix-flatpak) are imported by the aspect that configures them. Non-module files
stay outside modules/: hardware/<host>.nix holds the generated hardware configuration and
wallpaper.png the wallpaper.
For now I'm assuming that you are setting up the disk with a boot partition and a root partition divided in four submodules: root, home, nix and swap.
nix-shell -p btrfs-progs
# Setup the two partitions
sudo fdisk /dev/sdx
# Format and label the two partitions
sudo mkfs.fat -F32 /dev/sdx1
sudo fatlabel /dev/sdx1 NIXBOOT
sudo mkfs.btrfs /dev/sdx2
sudo btrfs filesystem label /dev/sdx2 NIXROOT
# Create the subvolumes
sudo mount /dev/sdx2 /mnt
sudo btrfs subvolume create /mnt/{root,home,nix,swap}
sudo umount /mnt
# Mount everything
sudo mount -o compress=zstd,subvol=root /dev/sdx2 /mnt
sudo mount --mkdir -o compress=zstd,subvol=home /dev/sdx2 /mnt/home
sudo mount --mkdir -o compress=zstd,noatime,subvol=nix /dev/sdx2 /mnt/nix
sudo mount --mkdir -o noatime,subvol=swap /dev/sdx2 /mnt/swap
sudo mount --mkdir /dev/sdx1 /mnt/boot
sudo truncate -s 0 /mnt/swap/swapfile
sudo chmod 0600 /mnt/swap/swapfile
sudo chattr +C /mnt/swap/swapfile
sudo dd if=/dev/zero of=/mnt/swap/swapfile bs=1G count=4 status=progress # Change the block size and count to match the desired swapfile size
sudo mkswap /mnt/swap/swapfile
sudo swapon /mnt/swap/swapfileNow that you have setup the disk you want to clone the dotfiles repository to your desired folder. Right now all of my systems are single-user so for simplicity I place it in /home/<user>/.dotfiles.
sudo mkdir -p /mnt/home/davide
git clone https://github.com/ITHackerstein/dotfiles /mnt/home/davide/.dotfilesOnce you've done this add a file for the new system in modules/hosts (see the existing ones) and generate its hardware configuration.
sudo nixos-generate-config --root /mnt --show-hardware-config > /path/to/dotfiles/hardware/new-host.nixChange the file systems to match the options used above and also labels for simplicity.
Finally, you can install the system:
sudo nixos-install --root /mnt --flake /path/to/dotfiles#new-hostOnce installed, remember to change the permissions of the dotfiles if you don't want them to be owned by root:
sudo nixos-enter --root -c /mnt 'chown -R <user>:users /path/to/dotfiles'And, as a last step, remember to change the password of each user:
sudo nixos-enter --root -c /mnt 'passwd <user>'Now you can reboot the system, open a shell for the user and run
home-manager switch --flake /path/to/dotfiles