Personal NixOS & nix-darwin configuration with a modular, hierarchical architecture.
"Works on my machine" → "Works on every machine"
Nix is a purely functional package manager that treats system configuration as code. The same configuration always produces the same system — whether you're setting up a fresh laptop or rebuilding after a disaster. Made a mistake? Just boot into a previous generation and you're back to a working state in seconds.
Everything is declarative: packages, services, dotfiles, even your desktop environment. No more scattered configs or forgotten setup steps. Your entire system lives in version-controlled .nix files that work across all your machines — Linux desktops, macOS laptops, headless servers.
Updates are atomic (they fully apply or don't touch anything), and different package versions coexist peacefully. No dependency hell, no "I updated X and now Y is broken". Just reproducible, reliable systems.
- 🖥️ Multi-platform — Same structure for NixOS and macOS (nix-darwin)
- 👥 Multi-user ready — Each user can have different modules enabled
- 🎯 Hierarchical enables — Enable at any path level:
home.browsers.enableorhome.browsers.vivaldi.enable - ✏️ Live-editable dotfiles — Config files are symlinked to this repo, edit in place without rebuild
- 🔍 Auto-discovery — Drop a
.nixfile in any module directory, it's automatically imported
# Clone the repository
git clone https://github.com/gdr/dot.git ~/Workspaces/gdr/dot
cd ~/Workspaces/gdr/dot
# Apply configuration
# NixOS:
sudo nixos-rebuild switch --flake .#<hostname>
# macOS:
darwin-rebuild switch --flake .#<hostname>.
├── flake.nix # Entry point - defines hosts and imports
├── hosts/
│ ├── users/ # User defaults (imported by machines)
│ │ └── dgarifullin.nix
│ └── machines/ # Machine configurations
│ ├── nix-goldstar/ # NixOS host
│ │ ├── default.nix
│ │ └── hardware-configuration.nix
│ └── mac-brightstar/ # Darwin host
│ └── default.nix
├── lib/
│ └── default.nix # Helper functions (mkModule, mkDotfilesSymlink)
├── modules/
│ ├── _core/ # Core module infrastructure
│ │ ├── registry.nix # Module registry builder
│ │ └── user.nix # hostUsers options & home-manager setup
│ ├── systems/
│ │ ├── all/ # Cross-platform system modules
│ │ │ ├── fonts.nix
│ │ │ ├── nix/
│ │ │ │ ├── gc.nix
│ │ │ │ └── settings.nix
│ │ │ └── shell/
│ │ │ ├── git.nix
│ │ │ └── ssh.nix
│ │ ├── linux/ # Linux-only system modules
│ │ │ ├── desktop/
│ │ │ │ ├── awesomewm/
│ │ │ │ └── hyprland/
│ │ │ ├── graphics/
│ │ │ ├── keyboards/
│ │ │ ├── networking/
│ │ │ └── sound.nix
│ │ └── darwin/ # macOS-only system modules
│ └── home/ # User-level modules (enabled hierarchically)
│ ├── browsers/
│ ├── cli/
│ ├── desktop/
│ │ ├── appearance/
│ │ ├── services/
│ │ ├── utils/
│ │ └── widgets/
│ ├── editors/
│ ├── games/
│ ├── media/
│ ├── messengers/
│ ├── security/
│ ├── shell/
│ └── terminal/
└── pkgs/ # Custom packages
| Type | Location | Enabled via | Scope |
|---|---|---|---|
| System (All) | systems/all/ |
systemAll.<name>.enable |
System-wide, cross-platform |
| System (Linux) | systems/linux/ |
systemLinux.<name>.enable |
System-wide, Linux only |
| System (Darwin) | systems/darwin/ |
systemDarwin.<name>.enable |
System-wide, macOS only |
| User | home/ |
hostUsers.<user>.modules.<path>.enable |
Per-user, hierarchical enables |
- Create host directory:
mkdir -p hosts/machines/my-new-host- Create
default.nix:
# hosts/machines/my-new-host/default.nix
{ config, lib, pkgs, ... }:
let
importUser = name: import ../../users/${name}.nix { inherit lib; };
in
{
imports = [ ./hardware-configuration.nix ];
# User configuration
hostUsers.dgarifullin = importUser "dgarifullin" // {
enable = true;
keys = [{
name = "my-new-host";
type = "rsa";
purpose = [ "git" "ssh" ];
isDefault = true;
}];
# Hierarchical module enables
modules = {
home.cli.enable = true;
home.shell.enable = true;
home.editors.enable = true;
# Or enable specific modules:
# home.browsers.vivaldi.enable = true;
};
};
networking.hostName = "my-new-host";
# System modules
systemAll = {
fonts.enable = true;
nix.settings.enable = true;
nix.gc.enable = true;
shell.ssh.enable = true;
shell.git.enable = true;
};
# Linux-specific (remove for Darwin)
systemLinux = {
desktop.hyprland.enable = true;
networking.networkmanager.enable = true;
sound.enable = true;
};
time.timeZone = "Europe/Moscow";
}- Generate hardware config (NixOS):
nixos-generate-config --show-hardware-config > hosts/machines/my-new-host/hardware-configuration.nix- Add to
flake.nix:
nixosConfigurations.my-new-host = mkNixosConfiguration ./hosts/machines/my-new-host;
# or for Darwin:
darwinConfigurations.my-new-host = mkDarwinConfiguration ./hosts/machines/my-new-host;- Create user defaults:
# hosts/users/newuser.nix
{ lib, ... }:
{
enable = lib.mkDefault false;
fullName = lib.mkDefault "New User";
email = lib.mkDefault "newuser@example.com";
github = lib.mkDefault "newuser";
extraGroups = lib.mkDefault [ "wheel" "audio" "video" ];
}- Enable in host config:
# hosts/machines/my-host/default.nix
hostUsers.newuser = importUser "newuser" // {
enable = true;
keys = [{
name = "my-host";
type = "rsa";
purpose = [ "git" "ssh" ];
isDefault = true;
}];
# Hierarchical module enables
modules = {
home.core.enable = true;
home.shell.enable = true;
home.media.vlc.enable = true; # specific module
};
};Configure modules per-user using hierarchical enables:
hostUsers.dgarifullin = importUser "dgarifullin" // {
enable = true;
modules = {
# Enable entire categories
home.browsers.enable = true; # enables vivaldi, chromium, etc.
home.editors.enable = true; # enables neovim, cursor, etc.
# Or enable specific modules
home.media.vlc.enable = true; # just vlc
home.media.spotify.enable = true;
};
};Hierarchical enables:
home.enable = true→ enables ALL home moduleshome.browsers.enable = true→ enables all browsershome.browsers.vivaldi.enable = true→ enables just vivaldi
Module paths follow the directory structure: home.<category>.<module-name>
# modules/home/tools/my-tool.nix
{ lib, pkgs, ... }@args:
lib.my.mkModuleV2 args {
description = "My awesome tool";
platforms = [ "linux" "darwin" ]; # optional, defaults to both
module = {
# Cross-platform config (goes to home-manager.users.*)
allSystems.home.packages = [ pkgs.my-tool ];
# Or platform-specific
nixosSystems.programs.my-tool.enable = true;
darwinSystems.homebrew.casks = [ "my-tool" ];
};
}# modules/systems/linux/services/my-service.nix
{ lib, pkgs, config, ... }@args:
let
enabledUsers = lib.filterAttrs (_: u: u.enable) config.hostUsers;
in
lib.my.mkSystemModuleV2 args {
namespace = "linux";
description = "My service";
module = _: {
# System-level NixOS options
services.my-service.enable = true;
# User packages via home-manager
home-manager.users = lib.mapAttrs (name: _: {
home.packages = [ pkgs.my-tool-client ];
}) enabledUsers;
};
}Modules are auto-discovered recursively! Just create your .nix file in the right directory and it's automatically imported. No manual import lists needed.
Store config files in the repo and symlink them so you can edit without rebuilding:
modules/home/terminal/ghostty/
├── ghostty.nix
└── dotfiles/
├── config
└── themes/
└── catppuccin-mocha
In your module, use mkDotfilesSymlink:
{ config, pkgs, lib, self, ... }:
{
config = mkIf cfg.enable (mkMerge [
# Install the package
(mkModule { allSystems.home.packages = [ pkgs.ghostty ]; })
# Symlink dotfiles to ~/.config/ghostty (editable without rebuild!)
{
home-manager.users = lib.my.mkDotfilesSymlink {
inherit config self;
path = "ghostty"; # ~/.config/ghostty
source = "modules/home/terminal/ghostty/dotfiles"; # repo path
};
}
]);
}Now ~/.config/ghostty → /path/to/repo/modules/home/terminal/ghostty/dotfiles
Edit the files directly, changes apply immediately (no nixos-rebuild needed)!
| Host | Platform | Description |
|---|---|---|
nix-goldstar |
NixOS | Desktop workstation with Hyprland |
mac-italy |
Darwin | MacBook Pro |
mac-blackstar |
Darwin | Mac Mini |
Enable modules hierarchically per-user:
hostUsers.myuser.modules = {
home.browsers.enable = true; # enables all browsers
home.core.enable = true; # enables htop, shell-utils
home.shell.enable = true; # enables zsh, tmux
home.editors.neovim.enable = true; # specific module
};| Path | Modules |
|---|---|
home.core |
htop, shell-utils (bat, fzf, wget, direnv) |
home.shell |
zsh with oh-my-zsh, zplug, tmux |
home.terminal |
ghostty |
home.browsers |
chromium, vivaldi |
home.editors |
cursor, neovim (nixvim) |
home.desktop |
rofi, dunst, brightnessctl, pamixer, wayland-utils |
home.media |
vlc, spotify |
home.messengers |
telegram |
home.games |
steam |
home.security |
keepassxc, bitwarden |
home.downloads |
qbittorrent |
home.virtualisation |
docker |
home.utils |
raycast (darwin), macfuse (darwin) |
MIT License - see LICENSE for details.