!wfudwzqQUiJYJnqfSY:nixos.org

NixOS Module System

160 Members
33 Servers

Load older messages


SenderMessageTime
14 Jan 2026
@bake.monorail:matrix.orgbake.monorail *

I'd need to spend some time on the implementation of the modules system to be of some help.
I've no idea what the check function is, for instance.

I don't want to derail the discussion, but I'll just leave here my complaint that nix is lacking a type system and it's being reimplemented at run-time.
For instance, for "public API" functions I made up the following "type safe" function using the module system:

let
  typeSafeFunction =
    { options, implementation }:
    # Return a function that accepts some arguments
    arguments:
    # and invokes the implementation
    implementation
      # Passing as arguments the result of evaluating the module
      (pkgs.lib.evalModules {
        modules = [
          {
            inherit options;
            config = arguments;
          }
        ];
      }).config;
      xxx = typeSafeFunction {
        options = { arg1 = mkOption { ...}; };
        implementation = { arg1 }: arg1 +1;
      };
in
  xxx { arg1 = 3; }

Which is a bit absurd.

It seems to me that the general feeling in the community is that nix won't get a type system any time soon. Maybe we need something like TypeScript, a TypeNix transpiler. I'm sure there already are some efforts like that.

09:18:11
@bake.monorail:matrix.orgbake.monorail *

I'd need to spend some time on the implementation of the modules system to be of some help.
I've no idea what the check function is, for instance.

I don't want to derail the discussion, but I'll just leave here my complaint that nix is lacking a type system and it's being reimplemented at run-time.
For instance, for "public API" functions I made up the following "type safe" function using the module system:

let
  typeSafeFunction =
    { options, implementation }:
    # Return a function that accepts some arguments
    arguments:
    # and invokes the implementation
    implementation
      # Passing as arguments the result of evaluating the module
      (pkgs.lib.evalModules {
        modules = [
          {
            inherit options;
            config = arguments;
          }
        ];
      }).config;
  xxx = typeSafeFunction {
    options = { arg1 = mkOption { ...}; };
    implementation = { arg1 }: arg1 +1;
  };
in
  xxx { arg1 = 3; }

Which is a bit absurd.

It seems to me that the general feeling in the community is that nix won't get a type system any time soon. Maybe we need something like TypeScript, a TypeNix transpiler. I'm sure there already are some efforts like that.

09:18:42
@mattsturg:matrix.orgMatt Sturgeon

Any reading material you suggest? Maybe there's a guide about internals of the modules type system.

Honestly, you'll get much more out of experiments with things like nix repl, nix eval (or nix-instantiate --eval), reading the relevant code in nixpkgs, etc.

I've no idea what the check function is, for instance.

The check function is what the module system uses to check "does this definition match this type". Every type has a check function.

$ nix repl
Nix 2.31.2+2
Type :? for help.
nix-repl> lib = import <nixpkgs/lib>

nix-repl> myType = lib.types.submodule {}

nix-repl> myType.check {}
true

nix-repl> myType.check ./file
true

nix-repl> myType.check ({ lib, ... }: {})
true

nix-repl> myType.check null
false

If you're curious about impl, you can use the repl to find where something is defined too:

nix-repl> builtins.unsafeGetAttrPos "check" myType
{
  column = 11;
  file = "/nix/store/ln4j1iqnnzs2ynx2cr88bdh65fmds2aq-source/lib/types.nix";
  line = 280;
}

nix-repl> :doc myType.check
Function __functor
… defined at
/nix/store/ln4j1iqnnzs2ynx2cr88bdh65fmds2aq-source/lib/types.nix:1271:32

Because we currently use check as union discriminator.

I.e., "union" types (like either, oneOf, nullOr, etc) use the provided types' check functions to check if a definition is of that type. If no permitted type matches check its throws an error, if any match, the first matching type is used.

In this way, it'd be useless to declare an either type with two types that both "check" for the same thing.

As I said before, you can work around this using lib.types.addCheck which allows you to add additional conditions to a type's check function. The NixOS manual has an example of extending a type's check and an example of overriding it.

we should do something along !merged.headError && discriminator merged.value

This is a proposal for how union types can be smarter, by taking advantage of v2 check&merge. Essentially, the v2 system was recently added to Nixpkgs and combines the checking and merging responsibility into a single function called merge.v2. The v2 interface allows definition merging to return additional metadata, such as whether merging encountered any errors.

hsjobeki is suggesting that Nixpkgs could distinguish between a union of submodules by selecting the first one that can handle the definition without errors. That's probably a more useful default behavior, although it may have a performance cost and still wouldn't cover all scenarios. E.g. some scenarios don't have a sensible solution; how to handle a module-definition that doesn't define any options? Or defines options that'd be valid in multiple submodule configurations? Or a module that declares additional options? Or how to handle freeform submodules?

19:15:24
@bake.monorail:matrix.orgbake.monorail

builtins.unsafeGetAttrPos

:O :O :O

20:46:55
17 Jan 2026
@majiir:matrix.orgMajiir Paktu I can set internal on an option to make it usable only in nixpkgs. Is there any mechanism to do the opposite, where an option is unusable in-tree but still available to users? The use case is for an option that should be deprecated, but where the replacement is not yet stable enough to produce a warning and steer users toward it. But also, the replacement is widely used within nixpkgs already. 02:25:32
@hexa:lossy.networkhexawarnings02:27:04
@mattsturg:matrix.orgMatt Sturgeon internal doesn't not affect who can use an option. It only affects whether it is documented. It's effectively the same thing as visible = "shallow". 12:30:52
@mattsturg:matrix.orgMatt Sturgeon * internal doesn't affect who can use an option. It only affects whether it is documented. It's effectively the same thing as visible = "shallow". 13:05:04
18 Jan 2026
@nam3l33ss:matrix.org·☽•Nameless☆•777 · ± changed their profile picture.14:58:52
@isabel:isabelroses.comisabel changed their profile picture.20:43:36
19 Jan 2026
@mpuppe:matrix.orgmpuppe joined the room.21:20:37
21 Jan 2026
@bake.monorail:matrix.orgbake.monorail is there anything more specific than types.str I can use for a version number that I will later compare with lib.versionAtLeast? 20:39:57
@mattsturg:matrix.orgMatt Sturgeon

In string types we have strMatching, however that expects a regex not a predicate function.

The general solution is addCheck (see extending types), however the examples there don't show that you typically also want to extend/override the type's description.

20:46:28
@bake.monorail:matrix.orgbake.monorail yeah, I went with strMatching, but I was hoping to have a type matching exactly what versionAtLeast would accept, but I guess there's no such a thing 20:50:21
@bake.monorail:matrix.orgbake.monorail versionAtLeast under the hood uses builtins.compareVersions, which seems to accept anything, probably it has a last-resort method comparison that's just lexicographic comparison 20:53:24
8 Feb 2024
@aciceri:nixos.devzrsk joined the room.10:38:02
15 Feb 2024
@a-kenji:matrix.orga-kenji joined the room.19:15:14
16 Feb 2024
@qyriad:matrix.orgQyriad joined the room.14:56:15
@mr-qubo:matrix.orgmr-qubo joined the room.14:59:24
@mr-qubo:matrix.orgmr-qubo

I recently stumbled upon similar issue when working on home-manager. https://discourse.nixos.org/t/is-it-possible-to-define-systemd-services-in-a-submodule/39538/5

The idea is that enabling https://nix-community.github.io/home-manager/options.xhtml#opt-programs.bash.enableCompletion should set environment.pathsToLink = [ "/share/bash-completion" ];.

I think that module system is missing an option to pass config options recursively up to all ancestors.

15:06:01
@mr-qubo:matrix.orgmr-qubo My idea is that nixos config could have a property extraNixosChildConfig and in home-manager bash module I could set _recurseAncestors = { extraNixosChildConfig = { environment.pathsToLink = [ ... ]; }; }. 15:07:22
@mr-qubo:matrix.orgmr-qubowdyt?15:07:26
@mr-qubo:matrix.orgmr-qubo * My idea is that nixos config could have a property extraNixosChildConfig that gets merged with the rest of the config and in home-manager bash module I could set _recurseAncestors = { extraNixosChildConfig = { environment.pathsToLink = [ ... ]; }; }. 15:07:44
@mr-qubo:matrix.orgmr-qubo * My idea is that nixos config could pick up extraNixosChildConfig from childs and merge it with the rest of the config and in home-manager bash module I could set _recurseAncestors = { extraNixosChildConfig = { environment.pathsToLink = [ ... ]; }; }. 15:08:21
@infinisil:matrix.orginfinisilNot sure about that recursive thing, that doesn't seem necessary, but yeah if there's something missing in the NixOS module for home-manager, that could be added15:34:09
@infinisil:matrix.orginfinisilSounds like an issue for the home-manager repo15:34:16
@mr-qubo:matrix.orgmr-quboYeah, we could add it just for home-manager. But is seems like the issue is quite generic. See also https://github.com/NixOS/nixpkgs/pull/152785.15:51:50
@infinisil:matrix.orginfinisilHmm yeah fair. I don't have the capacity to think a lot about this right now, it's a very intricate topic to wrap ones head around15:56:55
@mr-qubo:matrix.orgmr-quboYeah, I just wanted to bring the topic, maybe someone has some interesting thoughts.16:05:23
@philiptaron:matrix.orgPhilip Taron (UTC-8) joined the room.17:49:31

Show newer messages


Back to Room ListRoom Version: 10