A modular Home Manager configuration that works across multiple platforms:
- macOS laptops and desktops
- Linux servers and workstations
- Shared configurations with conditional overrides
-
Create a new repository using the default template:
nix flake new -t github:seandmr/nixfiles#default my-config cd my-config -
Customize the configuration in
flake.nixwith your settings:- Set your
usernameandhostname - Configure modules according to your preferences
- Update system architecture as needed
- Set your
-
Apply your configuration:
home-manager switch --flake .
- Install
nixand enableflakessupport - On macOS, install Homebrew
- Clone this repository to
~/nixfiles - Run the switch script to activate:
bin/switch
The script detects your current system and applies the correct configuration profile.
The configuration is organized as follows:
nixfiles/
├── bin/ # Helper scripts
│ └── switch # Activation script
├── flake.nix # Main entry point
├── hosts/ # Host-specific configurations
│ ├── m1-grizzly.nix # Personal macOS laptop
│ ├── work-mac.nix # Work laptop configuration
│ └── homelab.nix # Server configuration
├── lib/ # Configuration files and resources
│ ├── nvim/ # Neovim configuration
│ ├── zsh/ # ZSH configuration
│ └── ... # Other resources
├── modules/ # Modular configurations
│ ├── core.nix # Core options and imports
│ ├── darwin.nix # macOS-specific configuration
│ ├── desktop.nix # GUI applications and settings
│ ├── exclude-packages.nix # Package exclusion system
│ ├── git.nix # Git configuration
│ ├── neovim.nix # Neovim setup
│ ├── secrets.nix # Secret management
│ └── shell.nix # Terminal and shell setup
└── secrets/ # Secret files (gitignored)
Each module includes:
- An
enableoption to toggle it on/off - Configuration specific to its purpose
- Options for fine-grained control of module features
Each module has an enable option that controls whether the module is active. This is set in the host configuration file.
For example, to enable the desktop module:
modules.desktop.enable = true;The configuration is completely modular, with each host choosing which modules to enable without relying on system type flags.
The prepareHome function in flake.nix accepts the following configuration options:
prepareHome {
username = "user";
platform = "x86_64-linux"; # Renamed from system
stateVersion = "24.05";
# Module configurations...
shell = {};
neovim = {};
git = {};
desktop = {};
darwin = {};
excludePackages = [];
# Additional configuration through extraModules
extraModules = [
# Custom configuration modules
({ config, lib, pkgs, ... }: {
# Your direct configurations here
})
];
}When using with NixOS, always wrap the function call in parentheses:
# In your NixOS configuration
modules = [
(dotfiles.lib.nixosHome {
username = "user";
platform = "x86_64-linux";
stateVersion = "24.05";
# Module configurations...
})
];You can add custom configurations using the extraModules parameter:
extraModules = [
({ config, lib, pkgs, ... }: {
# Direct configuration for any home-manager settings
programs.starship = {
enable = true;
enableZshIntegration = true;
settings = {
add_newline = false;
};
};
xdg.configFile."myapp/settings.json".text = ''{ "theme": "dark" }'';
home.packages = with pkgs; [
ripgrep
fd
];
})
];The extraModules parameter is handled through the module system. Each module in the list
is imported automatically and its configuration is applied to your home-manager setup.
git = {
enable = true; # Enable/disable Git configuration
username = "Your Name"; # Git user.name
email = "your@email.com"; # Git user.email
extraConfig = { # Additional Git configuration
pull.rebase = true;
init.defaultBranch = "main";
};
};shell = {
zshrc = {
sourceExtension = ./path/to/additional.zsh; # Optional path to an additional zsh config file
append = ''
# Additional zsh configuration to append to zshrc
alias ll='ls -la'
export MY_ENV_VAR="value"
'';
};
};neovim = {
enable = true; # Enable/disable Neovim configuration
enableLlmTools = true; # Enable/disable AI coding assistants
extraPlugins = []; # Additional Vim plugins
extraPackages = []; # Additional system packages for Neovim
extraConfig = ''' # Additional Lua configuration
vim.opt.colorcolumn = "80"
''';
llmLuaOverride = null; # Optional path to custom LLM config
};desktop = {
enable = true; # Enable/disable desktop applications
ghostty.enable = true; # Enable/disable Ghostty terminal configuration
kitty.enable = true; # Enable/disable Kitty terminal configuration
vscode.enable = true; # Enable/disable VSCode configuration
};darwin = {
enable = true; # Enable macOS-specific configuration
brewfile = ./Brewfile; # Path to Homebrew bundle file
alfred.enable = true; # Enable Alfred configuration
karabiner.enable = true; # Enable Karabiner Elements configuration
};homeConfigurations."user@host" = lib.standaloneHome {
username = "user";
platform = "x86_64-linux";
stateVersion = "24.05";
git = {
username = "User Name";
email = "user@example.com";
};
neovim.enableLlmTools = false;
desktop = {
enable = true;
ghostty.enable = true;
kitty.enable = true;
vscode.enable = true;
};
# Custom configuration through extraModules
extraModules = [
({ config, lib, pkgs, ... }: {
home.file.".config/custom/settings.json".text = ''{ "setting": "value" }'';
home.packages = [ pkgs.ripgrep ];
home.sessionVariables = { EDITOR = "nvim"; };
programs.starship.enable = true;
})
];
};The Neovim configuration uses Nix for plugin management, not vim plugin managers:
-
Add plugins in
modules/neovim.nixin thepluginslist- For packages not in
pkgs.vimPlugins, usepkgs.vimUtils.buildVimPlugin - For GitHub plugins, use
nix-git-shato generate the sha256 hash
- For packages not in
-
Language servers go in
programs.neovim.extraPackages -
Neovim configuration is in
lib/nvim/
The Neovim configuration includes optional LLM integration with tools like CodeCompanion and Copilot:
- Enable/Disable LLM Tools: Set
neovim.enableLlmToolstotrueorfalsein your configuration - Custom LLM Configuration: Provide your own LLM setup with
neovim.llmLuaOverride
Example configuration:
neovim = {
enable = true;
enableLlmTools = true; # Set to false to disable LLM tools entirely
# Optional: provide a custom LLM configuration
llmLuaOverride = ./path/to/custom-llms.lua;
};This flake includes a comprehensive test suite that verifies all configuration options work correctly. The tests can be run on any system without actually switching configurations.
The simplest way to run tests is using the provided script:
# Run all tests
bin/test
# Run specific test groups
bin/test minimal # Minimal configuration tests
bin/test complete # Complete configuration tests with all options
bin/test standalone # Standalone home-manager tests
bin/test nixos # NixOS integration tests
bin/test exclude # Package exclusion testYou can also run tests directly with Nix:
# Run all tests
nix build .#packages.$(nix eval --impure --expr "builtins.currentSystem").tests
# Run specific tests
nix build .#packages.$(nix eval --impure --expr "builtins.currentSystem").tests.testStandaloneComplete
nix build .#packages.$(nix eval --impure --expr "builtins.currentSystem").tests.testNixosComplete
nix build .#packages.$(nix eval --impure --expr "builtins.currentSystem").tests.testExcludePackagesThe tests simulate consuming this flake from another flake and verify that these configurations can be properly evaluated:
testStandaloneComplete- A comprehensive standalone home-manager configuration with all options enabledtestStandaloneMinimal- A minimal standalone home-manager configuration with only required optionstestNixosComplete- A comprehensive NixOS configuration with home-manager integration and all options enabledtestNixosMinimal- A minimal NixOS configuration with home-manager integrationtestExcludePackages- A configuration testing the package exclusion functionality
When developing a flake that uses this configuration as a dependency, you can verify that your configuration builds correctly without switching to it:
# For standalone home-manager configuration
nix build .#homeConfigurations.<username>@<hostname>.activationPackage --no-link
# For NixOS configuration
nix build .#nixosConfigurations.<hostname>.config.system.build.toplevel --no-link