Skip to content

Schema

Each of host, user, home configuration objects have freeform-types, meaning you can assign any attribute into them as meta-data.

However, at times you might want to have shared meta-data between all hosts or all users.

The base modules, den.schema.* serve for this purpose. They are not aspects, they are meta-data (the attributes of host) that aspects can later read for providing configuration.

For example, instead of:

den.hosts.x86_64-linux.igloo = {
hardened = true; # custom free-form metadata
# repetitive
users.alice.classes = [ "homeManager" ];
users.bob.classes = [ "homeManager" ];
};

You can do:

# This is not an aspect, it is a meta-configuration of the host capabilities.
den.schema.host = { host, lib, ... }: {
options.hardened = lib.mkEnableOption "Is it secure";
config.hardened = lib.mkDefault true;
};
# The meta-configuration module for all users
den.schema.user = { user, lib, ... }: {
config.classes = lib.mkDefault [ "homeManager" ];
};

All hosts you create will be hardened = true by default. And aspects will be able to read host.hardened value.

Base modules merged into all hosts, users, or homes. den.schema is built on top of gen-schema — each key is a schema entity, and the registry exposes introspection attrs (e.g. _kindNames, _topology, _edges) that the pipeline itself consumes.

OptionTypeDescription
den.schema.confdeferredModuleApplied to host, user, and home
den.schema.hostdeferredModuleApplied to all hosts (imports conf)
den.schema.userdeferredModuleApplied to all users (imports conf)
den.schema.homedeferredModuleApplied to all homes (imports conf)
den.schema.aspectdeferredModuleApplied to all aspects (imported into every aspect submodule) — where den.lib.strict is applied for strict mode
den.schema.conf = { lib, ... }: {
# shared across all host/user/home declarations
};
den.schema.host = { ... }: {
# host-specific base config
};

A schema entry also accepts attributes, stripped before the module merge and consumed by the resolution pipeline:

AttributeTypeDefaultDescription
includeslistOf raw[]Aspects/policies activated for every entity of this kind
excludeslistOf raw[]Aspects/policies suppressed for every entity of this kind
isEntityboolcomputedWhether the kind is a real entity (fan-out/policy target). Computed as true when the entry carries any content beyond collection keys; set it explicitly for content-free entity kinds (e.g. den.schema.flake-parts.isEntity = true)
isolatedboolfalseMark this kind’s scopes as isolated — when an ancestor collects its subtree, it cannot cross into an isolated scope (the isolated scope still collects its own content)
parentnullOr strnullThe enclosing entity kind (e.g. user.parent = "host"). Defines the entity schema DAG the pipeline uses for descendant fan-out and class-module arg promotion
collisionPolicynullOr enumnullClass-module collision policy for every entity of this kind (see Class Modules)
# Activate a policy for every host
den.schema.host.includes = [ den.policies.host-to-peers ];

See Policy Activation for how includes drives activation.

Entity kinds (host, user, home) are derived from the keys of den.schema. The pipeline uses the kind name to dispatch policies and resolve entities. Adding a key to den.schema registers a new entity kind. Den pre-registers fleet as an empty kind used by the diagram and fleet-view machinery.

Type: attrsOf systemType

Keyed by system string (e.g., "x86_64-linux"). Each system contains host definitions as freeform attribute sets.

den.hosts.x86_64-linux.myhost = {
users.vic = {};
};

The system level can be omitted: declare system inside the host value and Den normalizes it into the two-level form. Both forms coexist freely:

# Equivalent to den.hosts.x86_64-linux.myhost = { ...; };
den.hosts.myhost = {
system = "x86_64-linux";
users.vic = {};
};
OptionTypeDefaultDescription
namestrattr nameConfiguration name
hostNamestrnameNetwork hostname
systemstrparent keyPlatform (e.g., x86_64-linux)
classstrauto"nixos" or "darwin" based on system
aspectrawden.aspects.<name>Resolved aspect attrset for this host
descriptionstrautoclass.hostName@system
resolvedrawautoResolved aspect from context pipeline (see below)
usersattrsOf userType{}User accounts on this host
collisionPolicynull | enumnullClass module collision policy for this entity: "error", "den-wins", or "class-wins". See Class Modules.
instantiaterawautoOS builder function
intoAttrlistOf strautoFlake output path
*den.schema.host optionsOptions from base module
*free-form attributes
ClassDefault
nixosinputs.nixpkgs.lib.nixosSystem
darwininputs.darwin.lib.darwinSystem
systemManagerinputs.system-manager.lib.makeSystemConfig
ClassDefault
nixos[ "nixosConfigurations" name ]
darwin[ "darwinConfigurations" name ]
systemManager[ "systemConfigs" name ]

Type: attrsOf userType

OptionTypeDefaultDescription
namestrattr nameUser configuration name
userNamestrnameSystem account name
classeslistOf str[ "user" ]Nix classes this user participates in
aspectrawden.aspects.<name>Resolved aspect attrset
hostrawparent hostThe host this user belongs to
collisionPolicynull | enumnullClass module collision policy: "error", "den-wins", or "class-wins". See Class Modules.
resolvedrawautoResolved aspect from context pipeline (see below)
*den.schema.user optionsOptions from base module
*free-form attributes

Freeform: additional attributes pass through to the user module.

Type: attrsOf homeSystemType

Standalone home-manager configurations, keyed by system string. A key of the form user@host binds the home to an existing host’s user; a bare key declares an unbound standalone home.

den.homes.x86_64-linux.vic = {};

As with den.hosts, the system level can be omitted — put system inside the home value (both forms coexist):

den.homes."tux@igloo" = {
system = "x86_64-linux";
};
OptionTypeDefaultDescription
namestrparsed nameHome configuration name (the part before @ in a user@host key)
userNamestrparsed nameUser account name
hostNamenull | strparsed hostBound host name, or null for unbound standalone homes (the part after @)
hostrawresolved hostBound host entity, or null when standalone
userrawresolved userBound user entity, or null when standalone
systemstrparent keyPlatform system
classstr"homeManager"Home management class
aspectrawden.aspects.<name>Resolved aspect attrset
descriptionstrautohome.name@system
pkgsrawinputs.nixpkgs.legacyPackages.$sysNixpkgs instance
instantiaterawinputs.home-manager.lib.homeManagerConfigurationBuilder
collisionPolicynull | enumnullClass module collision policy: "error", "den-wins", or "class-wins". See Class Modules.
resolvedrawautoResolved aspect from context pipeline (see below)
intoAttrlistOf str[ "homeConfigurations" name ]Output path
*den.schema.home optionsOptions from base module
*free-form attributes

Every entity (host, user, home) has a resolved attribute — the aspect produced by running the entity through the resolution pipeline. This is auto-derived and used internally by mainModule to produce the entity’s final configuration.

Contribute Community Sponsor