# NixOS Configuration Guide This NixOS configuration repository uses a modular, hierarchical import structure to manage system and home-manager configurations across multiple environments and desktop setups. ## Table of Contents 1. [Architecture Overview](#architecture-overview) 2. [Directory Structure](#directory-structure) 3. [How Import Wranglers Work](#how-import-wranglers-work) 4. [Switching Environments](#switching-environments) 5. [Configuration Layers](#configuration-layers) 6. [Modifying Configurations](#modifying-configurations) --- ## Architecture Overview The configuration follows a **layered orchestrator pattern**: ``` flake.nix (entry point) ↓ configuration.nix (system orchestrator) ├─ hardware-configuration.nix (hardware specifics) ├─ modules/nixos/base/ (system-wide config) │ └─ default.nix (orchestrator) │ ├─ nix.nix │ ├─ boot.nix │ ├─ networking.nix │ ├─ users.nix │ ├─ services.nix │ ├─ programs.nix │ ├─ graphics.nix │ └─ packages.nix └─ modules/nixos/{i3wm,hyprland}/ (environment-specific) mun.nix (home-manager orchestrator) ├─ modules/home/i3wm/default.nix (orchestrator) │ ├─ dunst.nix │ ├─ i3.nix │ ├─ kitty.nix │ ├─ neovim.nix │ ├─ nnn.nix │ ├─ picom.nix │ ├─ polybar.nix │ ├─ rofi.nix │ ├─ scripts.nix │ └─ xdg.nix └─ modules/home/hyprland/default.nix (orchestrator) └─ chernobyl/default.nix (orchestrator) ├─ dunst.nix ├─ fastfetch.nix ├─ hyprland.nix └─ kitty.nix ``` --- ## Directory Structure ``` . ├── flake.nix # Flake inputs/outputs definition ├── flake.lock # Lock file for reproducibility ├── configuration.nix # Main system config (thin orchestrator) ├── hardware-configuration.nix # Hardware-specific config (generated) ├── mun.nix # Home-manager user config (orchestrator) ├── modules/ │ ├── nixos/ │ │ ├── base/ # Base system config (split modules) │ │ │ ├── default.nix # Orchestrator: imports all base modules │ │ │ ├── nix.nix # Nix settings, flakes, substituters │ │ │ ├── boot.nix # Boot loader, kernel, Plymouth │ │ │ ├── networking.nix # Hostname, NetworkManager, Bluetooth │ │ │ ├── users.nix # User definitions │ │ │ ├── services.nix # System services (SSH, Pipewire, Printing, Ly) │ │ │ ├── programs.nix # System programs (Firefox, Zsh, Steam) │ │ │ ├── graphics.nix # GPU drivers, hardware acceleration │ │ │ └── packages.nix # System-wide packages │ │ ├── i3wm/ │ │ │ └── default.nix # X11, i3 window manager config │ │ └── hyprland/ │ │ └── default.nix # Wayland, Hyprland config │ └── home/ │ ├── i3wm/ │ │ ├── default.nix # Orchestrator: imports all i3wm home modules │ │ ├── dunst.nix # Notification daemon (i3 config) │ │ ├── i3.nix # i3 window manager config (keybinds, layout) │ │ ├── kitty.nix # Terminal emulator (i3 config) │ │ ├── neovim.nix # Text editor with LazyVim setup │ │ ├── nnn.nix # File browser │ │ ├── picom.nix # X11 compositor │ │ ├── polybar.nix # Status bar (i3 specific) │ │ ├── rofi.nix # Application launcher │ │ ├── scripts.nix # Custom shell scripts │ │ └── xdg.nix # XDG MIME type defaults │ └── hyprland/ │ ├── default.nix # Orchestrator: imports Hyprland rices │ └── chernobyl/ # "Chernobyl" Hyprland rice │ ├── default.nix # Orchestrator for chernobyl rice │ ├── dunst.nix # Notification daemon (Hyprland config) │ ├── fastfetch.nix # System info display │ ├── hyprland.nix # Hyprland window manager config │ └── kitty.nix # Terminal emulator (Hyprland config) ``` --- ## How Import Wranglers Work An "import wrangler" is a `default.nix` file that acts as a **local aggregator**, collecting all related configurations into one place for easy management. This pattern appears at multiple levels: ### Level 1: Base System Configuration **File:** `modules/nixos/base/default.nix` ```nix { ... }: { imports = [ ./nix.nix ./boot.nix ./networking.nix ./users.nix ./services.nix ./programs.nix ./graphics.nix ./packages.nix ]; system.stateVersion = "25.11"; } ``` **Purpose:** Groups all foundational system configurations (boot, networking, users, services, packages) into a single import point. When you need to add a base system feature, you either: - Add it to an existing module file - Create a new module (e.g., `firewall.nix`) and add it to this import list **Benefits:** - Single import in `configuration.nix`: `./modules/nixos/base` - All base modules are in one place; easy to see what's included - New base modules are simply added to the imports list ### Level 2: Environment-Specific System Configuration **Files:** `modules/nixos/i3wm/default.nix`, `modules/nixos/hyprland/default.nix` These are currently thin wrappers but follow the same pattern. To extend them (e.g., add environment-specific services or packages), you would create sub-modules: ```nix # Example expansion of modules/nixos/i3wm/default.nix { ... }: { imports = [ ./xserver.nix # X11-specific settings ./i3.nix # i3 window manager ./keyboard.nix # Czech keyboard layout ]; } ``` ### Level 3: Home-Manager Orchestration **File:** `modules/home/i3wm/default.nix` ```nix { ... }: { imports = [ ./dunst.nix ./i3.nix ./kitty.nix ./neovim.nix ./nnn.nix ./picom.nix ./polybar.nix ./rofi.nix ./scripts.nix ./xdg.nix ]; } ``` **Purpose:** All i3wm-specific home-manager modules (dunst, i3 keybinds, polybar, etc.) are collected here. This is imported once in `mun.nix`, rather than importing 10 separate files. **Benefits:** - One line in `mun.nix`: `./modules/home/i3wm/default.nix` - All i3 home configs are clearly grouped - Easy to switch entire environments with a single comment/uncomment ### Level 4: Multi-Rice Support (Hyprland) **File:** `modules/home/hyprland/default.nix` ```nix { ... }: { imports = [ #./default.nix # main hyprland rice (future) ./chernobyl/default.nix # chernobyl hyprland rice ]; } ``` **File:** `modules/home/hyprland/chernobyl/default.nix` ```nix { ... }: { imports = [ ./dunst.nix ./fastfetch.nix ./hyprland.nix ./kitty.nix ]; } ``` **Purpose:** Supports multiple visual rices/themes for the same window manager. The parent orchestrator selects which rice to use. **Benefits:** - Scale to many rices easily (add `./cyberpunk/default.nix`, `./nord/default.nix`, etc.) - Each rice has its own folder with consistent structure - Switch rices by commenting/uncommenting in the parent orchestrator --- ## Switching Environments ### Switch from i3wm to Hyprland Edit **two files**: #### 1. System Configuration (`configuration.nix`) ```nix { config, lib, pkgs, ... }: { imports = [ ./hardware-configuration.nix ./modules/nixos/base # === Environment Choice === # Uncomment one of the following to select your environment: #./modules/nixos/i3wm # ← comment this ./modules/nixos/hyprland # ← uncomment this ]; } ``` #### 2. Home-Manager Configuration (`mun.nix`) ```nix { config, lib, pkgs, ... }: { imports = [ #./modules/home/i3wm/default.nix # ← comment this ./modules/home/hyprland/default.nix # ← uncomment this ]; # ... rest of mun.nix } ``` #### 3. Rebuild ```bash sudo nixos-rebuild switch ``` --- ## Configuration Layers The configuration is organized in **four distinct layers**: ### 1. **System-Wide Base (`modules/nixos/base/`)** Applied to **all environments**. **Includes:** - Nix settings (flakes, substituters) - Boot configuration (GRUB, EFI, kernel) - Networking (hostname, NetworkManager, Bluetooth) - Users (mun user definition) - System services (SSH, Pipewire, Printing, Ly display manager) - System programs (Firefox, Zsh, Steam) - Graphics drivers (Intel VAAPI, hardware acceleration) - System packages (Neovim, Git, TeX Live, RetroArch, etc.) **Modify by:** Editing existing files in `base/` or creating new ones and adding them to `base/default.nix`. ### 2. **Environment-Specific System (`modules/nixos/{i3wm,hyprland}/`)** Applied to **one environment at a time** (X11 vs Wayland). **i3wm includes:** - X11 enable - i3 window manager - Keyboard layout (Czech) - Display manager session **Hyprland includes:** - X11 disable - Hyprland enable - XDG portal for Wayland - Qt6 Wayland support - Keyboard layout (Czech) **Modify by:** Editing the respective `default.nix` or creating sub-modules. ### 3. **Home-Manager User-Wide Config (`mun.nix`)** Configuration applied to user `mun` only. **Includes:** - SSH setup - Shell configuration (Zsh with oh-my-zsh) - Environment variables - Gnome-keyring service - User packages (Rust tools, Discord, utilities) - Environment-specific home-manager orchestrator import **Modify by:** Editing `mun.nix` directly or adding packages to the `packages` list. ### 4. **Environment-Specific Home-Manager (`modules/home/{i3wm,hyprland}/`)** Applied to **one environment at a time**. **i3wm includes:** - i3 keybindings and layout - Polybar status bar - Dunst notifications - Picom compositor - Rofi launcher - NeoVim with LazyVim - Kitty terminal - Custom scripts - XDG MIME type defaults **Hyprland (chernobyl rice) includes:** - Hyprland config - Dunst notifications - Kitty terminal - Fastfetch system info **Modify by:** Editing the respective module files or adding new ones to the orchestrator `default.nix`. --- ## Modifying Configurations ### Add a New System Package **File:** `modules/nixos/base/packages.nix` ```nix environment.systemPackages = with pkgs; [ # ... existing packages ... my-new-package # ← add here ]; ``` ### Add a New Base System Service **File:** `modules/nixos/base/services.nix` or create `modules/nixos/base/firewall.nix` If adding firewall rules, create a new file: ```nix # modules/nixos/base/firewall.nix { config, lib, pkgs, ... }: { networking.firewall.allowedTCPPorts = [ 80 443 ]; } ``` Then add to orchestrator: ```nix # modules/nixos/base/default.nix { ... }: { imports = [ ./nix.nix ./boot.nix ./networking.nix ./users.nix ./services.nix ./programs.nix ./graphics.nix ./packages.nix ./firewall.nix # ← add here ]; system.stateVersion = "25.11"; } ``` ### Add an i3wm Home-Manager Module **File:** `modules/home/i3wm/my-new-config.nix` ```nix { config, pkgs, ... }: { # Your home-manager config here } ``` Then add to orchestrator: ```nix # modules/home/i3wm/default.nix { ... }: { imports = [ ./dunst.nix ./i3.nix # ... other modules ... ./my-new-config.nix # ← add here ]; } ``` ### Add a New Hyprland Rice Create a new directory: ```bash mkdir modules/home/hyprland/cyberpunk ``` Add files: ```nix # modules/home/hyprland/cyberpunk/default.nix { ... }: { imports = [ ./dunst.nix ./hyprland.nix ./kitty.nix ]; } ``` Update parent orchestrator: ```nix # modules/home/hyprland/default.nix { ... }: { imports = [ #./default.nix ./chernobyl/default.nix #./cyberpunk/default.nix # ← uncomment to use ]; } ``` --- ## Rebuilding Your System After making changes: ```bash # Switch to new system configuration sudo nixos-rebuild switch # Or, test first (doesn't activate) sudo nixos-rebuild test # Show what changed sudo nixos-rebuild dry-run ``` To edit and rebuild in one step: ```bash # If you have the 'edit' alias from mun.nix edit sudo nixos-rebuild switch ``` --- ## Key Principles 1. **One Import Per Layer:** Each `default.nix` orchestrator imports related modules, reducing clutter in parent files. 2. **Separation of Concerns:** System config (nixos/) is separate from user config (home/); base is separate from environment-specific. 3. **Easy Environment Switching:** Change environments by commenting one line in `configuration.nix` and `mun.nix`. 4. **Scalability:** Adding new features (base services, home modules, rices) follows a consistent pattern of creating a file + adding it to the orchestrator. 5. **Clarity:** Each file has a clear purpose; finding where to modify something is straightforward. --- ## Example Workflow ### Goal: Add Firefox configuration to i3wm 1. Create `modules/home/i3wm/firefox.nix`: ```nix { config, pkgs, ... }: { programs.firefox = { enable = true; profiles.mun = { settings = { "browser.startup.homepage" = "about:home"; }; }; }; } ``` 2. Add to orchestrator in `modules/home/i3wm/default.nix`: ```nix imports = [ ./dunst.nix ./firefox.nix # ← add here ./i3.nix # ... rest ]; ``` 3. Rebuild: ```bash sudo nixos-rebuild switch ``` Done! Firefox is now configured for the i3wm environment. --- ## Troubleshooting ### "Module not found" error Check that all imports in `default.nix` files reference correct file paths. Use absolute paths from the module directory: - `./nix.nix` ✓ (correct) - `../base/nix.nix` ✓ (correct, relative to parent) - `/absolute/path/nix.nix` ✗ (avoid; use relative) ### Environment not loading after switch Ensure **both** `configuration.nix` and `mun.nix` have the same environment enabled (not one i3wm and one hyprland). ### Syntax errors in .nix files Use `nix flake check` to validate: ```bash nix flake check ``` --- ## References - [NixOS Manual - Configuration](https://nixos.org/manual/nixos/stable/) - [Home Manager Manual](https://nix-community.github.io/home-manager/) - [Nix Language](https://nixos.wiki/wiki/Nix_language)