My NixOS configuration using the den framework with flake-parts and import-tree.
├── flake.nix # Auto-generated by flake-file — do not edit directly
├── flake.lock # Lock file — updated via `nix flake update`
├── hosts/ # Hardware-generated configs (nixos-generate-config)
│ ├── void/hardware-configuration.nix
│ └── voidframe/hardware-configuration.nix
├── modules/
│ ├── flake-inputs.nix # Flake input declarations — edit here, then run `nix run .#write-flake`
│ ├── den.nix # Bootstraps den, den defaults: stateVersion, HM config, sharedModules, user shell, hostname battery
│ ├── nh.nix # Exposes nix run .#<host> flake apps (builds with nh)
│ ├── hosts.nix # Declares hosts and their attributes
│ ├── system/ # OS-level aspects (boot, locale, networking, systemd, packages, users)
│ ├── hardware/ # Hardware aspects (bluetooth, kernel, udev, print, streamcontroller, usb)
│ ├── security/ # Security aspects (sops, pcscd, gnome-keyring, ly)
│ ├── desktop/ # Desktop aspects (hyprland, stylix, noctalia, flatpak, fonts, gtk, xdg, clipboard, cursor, environment, firefox, thunar, …)
│ │ └── hypr/ # Hyprland sub-aspects (hyprland, hypridle, hyprpolkitagent, hyprshot)
│ ├── shell/ # Shell aspects (zsh, bat, btop, direnv, fastfetch, fzf, ghostty, git, jq, just, kitty, lazygit, lsd, nh, payrespects, tealdeer, yazi, zoxide)
│ ├── gaming/ # Gaming aspects (steam, mangohud, deadlock, wow)
│ ├── media/ # Media aspects (mpv, obs-studio, spicetify, ananicy, cava, easyeffects, noisetorch, pics, pipewire, network-drives)
│ ├── communication/ # Communication aspects (vesktop, email)
│ ├── home/ # Home-manager aspects (common, files, packages)
│ ├── nix/ # Nix daemon settings and overlays
│ ├── hosts/ # Host aspect definitions (one file per host)
│ │ ├── void/default.nix # void host aspect + system-only includes
│ │ └── voidframe/default.nix # voidframe host aspect + system-only includes
│ └── users/
│ └── neonvoid/neonvoid.nix # User aspect — all desktop/shell/app includes
└── secrets/ # SOPS age-encrypted secrets
| Host | Hardware | Role | Attributes |
|---|---|---|---|
| void | AMD Ryzen 9 9950X, RX 9070 XT | Desktop | isMultiMonitor=true |
| voidframe | AMD Ryzen 7 7840U, Framework 16 | Laptop | isLaptop=true |
- den Framework — auto-generates
nixosConfigurations, wires Home-Manager, provideshost/usercontext - import-tree — all
.nixfiles undermodules/are auto-discovered; no manual wiring needed - Aspect Pattern — every feature is a self-contained file with optional
nixosandhomeManagersections - Host Context — freeform attributes on hosts (
isGaming,isLaptop,xRes, etc.) accessible in any aspect - User Context — user attributes (
userName,homeDirectory) accessible in any aspect - Hyprland — Wayland compositor, fully configured in
desktop/hypr/hyprland.nix - Stylix — System-wide theming (NixOS + HM in one aspect file)
- SOPS — Encrypted secrets, decrypted to
/run/secrets/at boot - Noctalia Shell — Quickshell bar, launcher, lock screen
- nh flake apps —
nix run .#void/nix run .#voidframefor building with nh
# Build (dry run)
nixos-rebuild dry-build --flake .#void
# Deploy
sudo nixos-rebuild switch --flake .#void
sudo nixos-rebuild switch --flake .#voidframe
# Or use the flake apps (builds with nh)
nix run .#void
nix run .#voidframe
# Update flake inputs
nix flake update
# Add or change a flake input: edit modules/flake-inputs.nix, then regenerate flake.nix
nix run .#write-flakeEach feature is a self-contained aspect file. NixOS and Home-Manager config for the same program live together:
# modules/audio/pipewire.nix
{ den, ... }:
{
den.aspects.pipewire = {
nixos = { pkgs, ... }: {
services.pipewire.enable = true;
};
homeManager = { ... }: {
# user-level config if needed
};
};
}To access host or user context, use the outer aspect lambda:
{ den, ... }:
{
den.aspects.example =
{ host, user, ... }:
{
nixos = { pkgs, ... }: {
# host.xRes, host.isMultiMonitor or false, host.isLaptop or false, etc.
# Note: networking.hostName is set automatically by den._.hostname
};
homeManager = { osConfig, ... }: {
# user.userName, user.homeDirectory, user.gitName, user.gitEmail, etc.
# osConfig accesses the NixOS config (e.g. osConfig.fileSystems ? "/games")
home.file."example".text = "hello ${user.userName}";
};
};
}Note:
hostanduserare only available in the outer aspect lambda, not insidenixos/homeManagermodule args. Capture them via Nix's lexical scoping (they are automatically in scope for inner lambdas).
Note: Host attributes are freeform — use
host.isLaptop or falsewhen an attribute may not exist on all hosts.
- Create
modules/<category>/my-feature.nix— import-tree picks it up automatically - Add
den.aspects.my-featureto the user's includes inmodules/users/neonvoid/neonvoid.nix(for user-facing features) or to the host's includes inmodules/hosts/<hostname>/default.nix(for system-only features) - Rebuild
# modules/category/my-feature.nix
{ den, ... }:
{
den.aspects.my-feature = {
nixos = { pkgs, ... }: {
services.myservice.enable = true;
};
homeManager = { pkgs, ... }: {
programs.myservice.enable = true;
};
};
}- Add the host to
modules/hosts.nix:
den.hosts.x86_64-linux = {
mynewhost = {
xRes = "1920";
yRes = "1080";
isLaptop = true; # freeform — any attributes you want
users.neonvoid = {};
};
};- Create
modules/hosts/mynewhost/default.nix:
{ den, inputs, ... }:
{
den.aspects.mynewhost = {
includes = [
# pick and choose aspects you want
den.aspects.boot
den.aspects.locale
den.aspects.networking
den.aspects.systemd
den.aspects.users
den.aspects.overlays
den.aspects.nixsettings
den.aspects.bluetooth
den.aspects.kernel
den.aspects.sops
den.aspects.ly
den.aspects.systempackages
];
nixos = { lib, ... }: {
imports = [ (inputs.self + "/hosts/mynewhost/hardware-configuration.nix") ];
# hostname is set automatically from den._.hostname (host name = "mynewhost")
# boot, hardware, networking specifics...
};
};
}- Add
hosts/mynewhost/hardware-configuration.nix(fromnixos-generate-config).
That's it — den auto-generates the nixosConfiguration output from hosts.nix.
- Create
modules/users/<username>/<username>.nix:
{ den, ... }:
{
den.aspects.<username> = {
includes = [
den.aspects.zsh
den.aspects.git
# ... all aspects this user should have, look at neonvoid for full list
];
nixos = { ... }: {
# den._.define-user, den._.primary-user, and den._.user-shell handle
# isNormalUser, shell, and wheel automatically — only add extras here
users.users.<username> = {
extraGroups = [ "audio" "video" "networkmanager" ];
};
};
};
}- Add the user to the host entry in
modules/hosts.nix:
mynewhost = {
users.<username> = {};
};See secrets/README.md. Secrets are age-encrypted and decrypted to /run/secrets/ at boot.