Documentation Index Fetch the complete documentation index at: https://mintlify.com/soriphoono/homelab/llms.txt
Use this file to discover all available pages before exploring further.
This guide covers creating custom modules for your homelab infrastructure. Modules are the building blocks that make your configuration reusable and maintainable.
Module Structure
Modules in this homelab are organized by scope:
modules/nixos/ - System-level NixOS modules
modules/home/ - User-level Home Manager modules
modules/droid/ - Nix-on-Droid modules
Each category is further organized by function:
modules/nixos/
├── core/ # Essential system functionality
├── desktop/ # Desktop environments and features
└── hosting/ # Server and hosting capabilities
modules/home/
├── core/ # Essential user configuration
└── userapps/ # User applications
Creating a Module
Create Issue
Follow the Issue-First policy: # Create issue: "feat: add bluetooth module for hardware support"
Create Feature Branch
git checkout -b dev-add-bluetooth-module
Choose Module Location
Decide where your module belongs based on its scope:
System hardware? → modules/nixos/core/hardware/
Desktop feature? → modules/nixos/desktop/features/
User application? → modules/home/userapps/
Create Module File
Create a new .nix file in the appropriate directory: touch modules/nixos/core/hardware/bluetooth.nix
Write Module Code
Follow the standard module pattern: modules/nixos/core/hardware/bluetooth.nix
{
lib ,
config ,
pkgs ,
...
}: let
cfg = config . core . hardware . bluetooth ;
in {
options . core . hardware . bluetooth = {
enable = lib . mkEnableOption "Enable bluetooth hardware support" ;
# Additional options
powerOnBoot = lib . mkOption {
type = lib . types . bool ;
default = true ;
description = "Power on bluetooth adapter on boot" ;
};
};
config = lib . mkIf cfg . enable {
hardware . bluetooth = {
enable = true ;
powerOnBoot = cfg . powerOnBoot ;
settings = {
General = {
Experimental = true ;
Enable = "Source,Sink,Media,Socket" ;
};
};
};
# Optional: Add packages
environment . systemPackages = with pkgs ; [
bluez
];
};
}
Register Module
Add your module to the appropriate default.nix file: modules/nixos/core/hardware/default.nix
{
imports = [
./bluetooth.nix
./adb.nix
./gpu
./hid
];
}
Validate Module
Test that your module compiles:
Commit Changes
Use conventional commits: git add modules/nixos/core/hardware/bluetooth.nix
git commit -m "feat: add bluetooth hardware module"
Module Patterns
Basic Enable Module
Simplest form - just an enable option:
{
lib ,
config ,
...
}: let
cfg = config . desktop . features . gaming ;
in {
options . desktop . features . gaming = {
enable = lib . mkEnableOption "Enable steam integration" ;
};
config = lib . mkIf cfg . enable {
environment . systemPackages = with pkgs ; [
moonlight-qt
];
};
}
Module with Options
Add configuration options:
{
lib ,
config ,
...
}: let
cfg = config . core . secrets ;
in {
options . core . secrets = {
enable = lib . mkEnableOption "Enable the core secrets module" ;
defaultSopsFile = lib . mkOption {
type = lib . types . nullOr lib . types . path ;
default = null ;
description = ''
The default secrets file to use for the secrets module.
This is used when no specific secrets file is provided.
'' ;
example = ./secrets.yaml ;
};
};
config = lib . mkIf cfg . enable {
sops . defaultSopsFile = lib . mkIf ( cfg . defaultSopsFile != null ) cfg . defaultSopsFile ;
};
}
Nested Module Structure
For complex features, use nested modules:
modules/nixos/desktop/environments/
├── default.nix
├── kde.nix
├── cosmic.nix
├── display_managers/
│ ├── default.nix
│ ├── sddm.nix
│ └── greetd/
│ └── default.nix
└── managers/
├── default.nix
└── hyprland.nix
Home Manager Module
User-level modules follow similar patterns:
{
lib ,
config ,
pkgs ,
...
}: let
cfg = config . userapps . browsers . firefox ;
in {
options . userapps . browsers . firefox = {
enable = lib . mkEnableOption "Enable Firefox browser" ;
};
config = lib . mkIf cfg . enable {
programs . firefox = {
enable = true ;
# Additional Firefox configuration
};
};
}
Module Best Practices
Use descriptive, lowercase names
Separate words with hyphens in filenames: bluetooth.nix, network-manager.nix
Use dot notation in option paths: core.hardware.bluetooth
Always use lib.mkEnableOption for boolean enables
Provide sensible defaults
Include descriptions for all options
Add example values where helpful
Use proper types: lib.types.str, lib.types.int, lib.types.path, etc.
Configuration Organization
Group related configuration together
Use let ... in for computed values
Keep config section clean and readable
Use lib.mkIf to conditionally apply configuration
Declare module inputs: lib, config, pkgs
Import other modules through default.nix files
Avoid circular dependencies
Testing Your Module
Local Testing
Test on a system configuration:
systems/test-system/default.nix
{
core . hardware . bluetooth . enable = true ;
}
Flake Checks
Ensure it passes validation:
Manual Validation
Build the configuration:
nix build .#nixosConfigurations.test-system.config.system.build.toplevel
Common Module Types
Hardware Module
Enables hardware support:
core . hardware . bluetooth . enable = true ;
core . hardware . gpu . dedicated . nvidia . enable = true ;
Service Module
Configures system services:
core . networking . tailscale . enable = true ;
core . networking . openssh . enable = true ;
Application Module
Installs and configures applications:
userapps . browsers . firefox . enable = true ;
userapps . development . editors . vscode . enable = true ;
Next Steps