Skip to main content
ClaudeWave
Skill75 estrellas del repoactualizado today

nix-module-system

Instalar en Claude Code
Copiar
git clone --depth 1 https://github.com/YPares/rigup.nix /tmp/nix-module-system && cp -r /tmp/nix-module-system/riglets/nix-module-system ~/.claude/skills/nix-module-system
Después abre una sesión nueva de Claude Code; el skill carga automáticamente.

SKILL.md

# Nix Module System: Dark Corners

Practical knowledge about `lib.evalModules` that's hard to find in official docs.

**Sources:**
- [nixpkgs/lib/modules.nix](https://github.com/NixOS/nixpkgs/blob/master/lib/modules.nix) — implementation
- [Module system docs](https://github.com/NixOS/nixpkgs/blob/master/doc/module-system/module-system.chapter.md) — official chapter
- [nix.dev deep dive](https://nix.dev/tutorials/module-system/deep-dive.html) — tutorial
- [noogle.dev evalModules](https://noogle.dev/f/lib/modules/evalModules) — function reference

## Module Identity & Deduplication

When the same module is included multiple times (e.g., via imports from different places), `evalModules` deduplicates by identity:

**Path-based modules**: Deduplicated by path string
```nix
modules = [ ./foo.nix ./foo.nix ];  # Same path → evaluated once
```

**Function/attrset modules**: Deduplicated by `key` attribute
```nix
# Without key: each inclusion is separate (can cause "defined multiple times" errors)
modules = [ myModule myModule ];  # Evaluated twice!

# With key: deduplicated
myModule = {
  key = "my-unique-module-id";
  imports = [ actualModule ];
};
modules = [ myModule myModule ];  # Evaluated once
```

Use `key` when you wrap modules dynamically and need deduplication across import chains.

## Module Arguments

### `_module.args` vs `specialArgs`

Both inject arguments into module functions, but differ in timing:

```nix
evalModules {
  specialArgs = { foo = "available during option declaration"; };
  modules = [{
    _module.args = { bar = "only available in config, not options"; };
  }];
}
```

| | `specialArgs` | `_module.args` |
|---|---|---|
| Available in `options = { ... }` | ✓ | ✗ |
| Available in `config = { ... }` | ✓ | ✓ |
| Can reference `config` | ✗ | ✓ |

**Rule of thumb**: Use `specialArgs` for things needed to *declare* options (like `lib`), use `_module.args` for runtime values (like `pkgs`).

### `_module.check`

Disable "unknown option" errors:
```nix
{ _module.check = false; }
```

Useful when modules set options that might not exist (e.g., optional integrations).

### `_module.freeformType`

Allow arbitrary attributes in config without declaring options:
```nix
{
  _module.freeformType = lib.types.attrsOf lib.types.anything;

  # Now any attribute is allowed without explicit options
  whatever.you.want = "works";
}
```

## Priority & Merging

### `mkDefault` / `mkForce` / `mkOverride`

Control which definition wins when multiple modules set the same option:

```nix
# Priority scale: lower number wins
lib.mkOverride 1000 "default priority"    # Same as mkDefault
lib.mkOverride 100 "normal priority"      # Default when no mk* used
lib.mkOverride 50 "force priority"        # Same as mkForce

# Shorthands
lib.mkDefault x  # mkOverride 1000 - easily overridden
lib.mkForce x    # mkOverride 50 - overrides most things
```

### `mkMerge`

Combine multiple config fragments:
```nix
config = lib.mkMerge [
  { services.foo.enable = true; }
  (lib.mkIf condition { services.foo.port = 8080; })
];
```

### `mkIf` (it's not just `if`)

`lib.mkIf` is *not* the same as Nix's `if`:
```nix
# Nix if: evaluated immediately, fails if option doesn't exist
config = if condition then { foo = 1; } else { };

# lib.mkIf: deferred, only evaluated if condition is true
config = lib.mkIf condition { foo = 1; };
```

`mkIf` prevents "infinite recursion" errors when the condition depends on other config values.

### `mkBefore` / `mkAfter` / `mkOrder`

For list-type options, control ordering:
```nix
{
  environment.systemPackages = lib.mkBefore [ earlyPkg ];  # Prepend
  environment.systemPackages = lib.mkAfter [ latePkg ];   # Append
  environment.systemPackages = lib.mkOrder 500 [ midPkg ]; # Explicit order
}
```

## Disabling Modules

Remove a module from evaluation:
```nix
{
  disabledModules = [
    "services/web-servers/nginx.nix"  # Path relative to modules root
    someImportedModule                 # Direct reference
  ];
}
```

Useful for replacing NixOS modules with custom implementations.

## Common Errors & Fixes

See [references/troubleshooting.md](references/troubleshooting.md) for detailed error explanations.

**Quick fixes:**
- "The option ... is defined multiple times" → Add `key` attribute or use `lib.mkForce`/`lib.mkMerge`
- "infinite recursion encountered" → Use `lib.mkIf` instead of `if`, or check for circular dependencies
- "The option ... does not exist" → Check spelling, or set `_module.check = false` for optional deps