Nix Module Development

SkillDev tools

Create and structure Nix modules for darwin, NixOS, or home-manager

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Nix Module Development skill

What this skill tells your AI

The instructions your AI receives, as published by r17x/universe in .claude/skills/nix/module/SKILL.md and read by ahel’s review.

Module Template

{ lib, config, pkgs, ... }:

let
  cfg = config.<namespace>.<name>;
in
{
  options.<namespace>.<name> = {
    enable = lib.mkEnableOption "<description>";

    package = lib.mkOption {
      type = lib.types.package;
      default = pkgs.<package>;
      description = "Package to use";
    };

    settings = lib.mkOption {
      type = lib.types.attrs;
      default = {};
      description = "Configuration settings";
    };
  };

  config = lib.mkIf cfg.enable {
    # Implementation here
  };
}

Common Option Types

lib.types.bool
lib.types.str
lib.types.int
lib.types.path
lib.types.package
lib.types.listOf lib.types.str
lib.types.attrsOf lib.types.str
lib.types.nullOr lib.types.str
lib.types.enum [ "a" "b" "c" ]
lib.types.submodule { options = { ... }; }

Module Patterns

Platform-specific config

config = lib.mkIf cfg.enable (lib.mkMerge [
  {
    # Common config
  }
  (lib.mkIf pkgs.stdenv.isDarwin {
    # macOS only
  })
  (lib.mkIf pkgs.stdenv.isLinux {
    # Linux only
  })
]);

Import platform modules

let
  platformModule = if pkgs.stdenv.isDarwin
    then ./darwin.nix
    else ./linux.nix;
in {
  imports = [ platformModule ];
}

Conditional imports

imports = lib.optional cfg.enableFeatureX ./feature-x.nix;

Darwin-specific

Launchd daemon

launchd.daemons.<name> = {
  script = ''
    exec ${lib.getExe cfg.package}
  '';
  serviceConfig = {
    RunAtLoad = true;
    KeepAlive = true;
  };
};

Launchd user agent

launchd.user.agents.<name> = {
  command = "${lib.getExe cfg.package}";
  serviceConfig.KeepAlive = true;
};

Home-manager specific

XDG config file

xdg.configFile."<app>/config".text = ''
  # config content
'';

Program module

programs.<name> = {
  enable = true;
  package = cfg.package;
  settings = cfg.settings;
};

Best Practices

  1. Use lib.mkEnableOption for enable flags
  2. Use lib.mkDefault for overridable defaults
  3. Use lib.mkForce sparingly, only when necessary
  4. Keep modules focused on single responsibility
  5. Document options with description
  6. Use lib.getExe for binary paths

Signals

GitHub stars
135
Forks
12
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
nix-module
Source
github.com/r17x/universe