Entities & Schema
What is an entity?
Section titled “What is an entity?”An entity is a typed data record — a host, a user, or a standalone home. Entities declare what exists in your infrastructure. They carry metadata consumed by policies (which define relationships) and aspects (which define behavior).
Entity types
Section titled “Entity types”Den provides three built-in entity types:
-
den.hosts— machines, keyed by<system>.<name>. Each host produces anixosConfigurations,darwinConfigurations, orsystemConfigsflake output depending on itsclass(auto-detected from the system platform). -
den.homes— standalone home-manager configurations for systems without root access, keyed by<system>.<name>. ProduceshomeConfigurationsoutputs. -
Users — declared inline on a host via
den.hosts.<sys>.<host>.users.<name>. Users are not top-level entities; they live within their host.
{ den.hosts.x86_64-linux.igloo.users = { alice = { }; bob = { }; };
den.homes.aarch64-darwin.alice = { };}Every entity carries a class that determines how it is instantiated and where its
output lands. For hosts this is "nixos" (auto-detected from x86_64-linux / aarch64-linux)
or "darwin" (from *-darwin); for homes it is "homeManager". Override with
class = "darwin" if auto-detection is wrong. Each entity also has an aspect field
that points to the aspect responsible for configuring it —
by default den.aspects.<name>.
Users have a classes list declaring which home-environment classes they want to use
(e.g., classes = [ "homeManager" ]).
Schema: shared options across a kind
Section titled “Schema: shared options across a kind”den.schema lets you define options that apply to every entity of a given kind.
There are three built-in schema kinds — host, user, and home — plus conf
which is shared across all three.
{ # Enable home-manager integration for all hosts den.schema.host.home-manager.enable = true;
# Add a custom option to every user den.schema.user = { user, lib, ... }: { options.groupName = lib.mkOption { default = user.userName; }; };
# Shared across all entity kinds den.schema.conf = { options.copyright = lib.mkOption { default = "Copy-Left"; }; };}Schema entries are deferredModule values — they can be plain attrsets with
options/config or functions that receive the entity’s module arguments.
Entity kinds and the resolution pipeline
Section titled “Entity kinds and the resolution pipeline”Each schema kind name (excluding conf and internal prefixes) is treated as a
first-class entity kind. Entity kinds automatically receive:
- A
resolvedattribute containing the fully resolved aspect output for that entity. - An
id_hashfor safe entity comparison (Nix’s==is fragile across module boundaries). - Context arguments derived from the entity’s module args, filtered to known kinds.
This is how the Data concern feeds into the resolution pipeline — entities declare what they are, and policies determine where behavior binds.
Per-entity policy activation
Section titled “Per-entity policy activation”Every entity (host, user, home) has a policies option — a list of policy names
to activate when that entity is resolved. Core policies (those marked _core = true)
are always active regardless.
{ # Activate a policy for all hosts of this kind den.schema.host.policies = [ "host-to-peers" ];
# Activate a policy for a specific host den.hosts.x86_64-linux.igloo.policies = [ "microvm-guests" ];}See Policies for how activation is used during resolution.
Freeform attributes
Section titled “Freeform attributes”Host, user, and home types all use freeformType, so you can attach arbitrary
data to any entity without declaring options first:
den.hosts.x86_64-linux.igloo = { gpu = "nvidia"; datacenter = "eu-west";};These attributes are accessible in aspects via the entity’s context argument:
den.aspects.igloo.includes = [ ({ host }: lib.optionalAttrs (host ? gpu) { nixos.hardware.nvidia.enable = true; })];For attributes that should exist on every entity of a kind with a default value,
prefer defining them in den.schema instead — this gives you type checking and
documentation. See the Schema reference for the full option
list, or the Declare Hosts & Users guide for practical examples.
Strict mode
Section titled “Strict mode”By default, Den allows freeform attributes on entities. Enable strict mode to
require that all entity attributes be declared via schema options:
{ # Enable strict mode for all hosts den.schema.host.strict = true;
# Now this would be an error — gpu is not a declared option: # den.hosts.x86_64-linux.igloo.gpu = "nvidia";}Strict mode is useful for larger configurations where you want to catch typos and enforce a consistent entity interface. Undeclared attributes produce an eval error with a message indicating which option is missing.