Files
nixpkgs/docs/guides/adding-modules.md
m3tm3re 03ad7451fc
Some checks failed
Update Nix Packages with nix-update / nix-update (push) Failing after 3h23m59s
feat: update documentation, lib functions, modules, and packages
2026-04-22 18:50:31 +02:00

5.6 KiB

Adding Modules Guide

How to add new NixOS and Home Manager modules to m3ta-nixpkgs.

Overview

Modules extend your system or user configuration with reusable, declarative options. m3ta-nixpkgs uses the standard NixOS module system with a m3ta.* namespace.

Quick Start

Use a template for quick setup:

# NixOS module
nix flake init -t .#nixos-module my-module

# Home Manager module
nix flake init -t .#home-manager-module my-module

This copies the template into templates/ — move it to the appropriate location and customize.

Adding a NixOS Module

1. Create the Module File

Create modules/nixos/<my-module>.nix:

{config, lib, pkgs, ...}:
with lib; let
  cfg = config.m3ta.myModule;
in {
  options.m3ta.myModule = {
    enable = mkEnableOption "my module description";
    # Add custom options here
    someOption = mkOption {
      type = types.str;
      default = "default-value";
      description = "Description of this option";
    };
  };

  config = mkIf cfg.enable {
    # System configuration goes here
    environment.systemPackages = [pkgs.some-package];

    # Or systemd services
    systemd.services.my-service = {
      enable = true;
      description = "My service";
      wantedBy = ["multi-user.target"];
      serviceConfig = {
        ExecStart = "${pkgs.some-package}/bin/some-daemon";
      };
    };
  };
}

2. Register in the Aggregator

Add to modules/nixos/default.nix:

{
  imports = [
    ./ports.nix
    ./mem0.nix
    ./<my-module>.nix   # ← add your module
  ];
}

3. Export from flake.nix

Add to the nixosModules output in flake.nix (optional, for direct import):

nixosModules = {
  default = ./modules/nixos;
  ports = ./modules/nixos/ports.nix;
  mem0 = ./modules/nixos/mem0.nix;
  my-module = ./modules/nixos/<my-module>.nix;  # ← add this
};

Adding a Home Manager Module

Home Manager modules are organized by category under modules/home-manager/.

Categories

Category Purpose Location
cli/ Command-line tools and utilities modules/home-manager/cli/
coding/ Development tools, editors, agents modules/home-manager/coding/
Root Cross-cutting concerns (e.g., ports) modules/home-manager/

1. Choose a Category

  • CLI tools (zsh plugins, tmux config, etc.) → cli/
  • Development tools (editor config, linters, etc.) → coding/
  • System-wide settings (ports, environment) → root level

2. Create the Module File

Create modules/home-manager/<category>/<my-module>.nix:

{config, lib, pkgs, ...}:
with lib; let
  cfg = config.m3ta.myModule;
in {
  options.m3ta.myModule = {
    enable = mkEnableOption "my user module description";
    someOption = mkOption {
      type = types.str;
      default = "value";
      description = "An option for this module";
    };
  };

  config = mkIf cfg.enable {
    home.packages = [pkgs.some-package];

    # Or Home Manager-specific options
    programs.zsh.enable = true;
  };
}

3. Register in the Category Aggregator

For cli/ modules, add to modules/home-manager/cli/default.nix:

{
  imports = [
    ./rofi-project-opener.nix
    ./stt-ptt.nix
    ./zellij-ps.nix
    ./<my-module>.nix   # ← add your module
  ];
}

For coding/ modules, add to modules/home-manager/coding/default.nix:

{
  imports = [
    ./editors.nix
    ./opencode.nix
    ./agents
    ./<my-module>.nix   # ← add your module
  ];
}

4. Export from flake.nix

Add to homeManagerModules in flake.nix:

homeManagerModules = {
  default = import ./modules/home-manager;
  my-module = import ./modules/home-manager/<category>/<my-module>.nix;  # ← add this
};

Module Patterns

Standard Enable Option

Always start with mkEnableOption:

options.m3ta.myModule = {
  enable = mkEnableOption "my module";
};

Conditional Configuration

Use mkIf for conditional config:

config = mkIf cfg.enable {
  # Only applied when enabled
};

Multiple Conditions

Use mkMerge when combining multiple conditional blocks:

config = mkMerge [
  (mkIf cfg.feature1.enable { ... })
  (mkIf cfg.feature2.enable { ... })
];

Nested Namespaces

For logically grouped options, use nested namespaces:

options.m3ta.coding = {
  myTool = {
    enable = mkEnableOption "my coding tool";
    # ...
  };
};

Usage: m3ta.coding.myTool.enable = true;

Shared Library Functions

For shared utilities (port helpers, etc.), import from lib/:

let
  portsLib = import ../../lib/ports.nix {inherit lib;};
  portHelpers = portsLib.mkPortHelpers { /* ... */ };
in {
  # use portHelpers
}

Documentation

Add documentation for your module:

  1. Create docs/modules/nixos/<my-module>.md (NixOS) or docs/modules/home-manager/<category>/<my-module>.md (HM)
  2. Follow the existing format in docs/modules/
  3. Add it to the appropriate overview page's "Available Modules" list
  4. Link it from docs/guides/using-modules.md

Testing

# Validate the module loads correctly
nix flake check

# Test with a minimal configuration (NixOS)
nixos-rebuild dry-build -I nixpkgs=. --option experimental-features flakes

# Format before commit
nix fmt