Skip to content

den.aspects

An attribute set of aspects. Each aspect key names an aspect; its value is an aspect set containing per-class deferred modules and optional includes and provides:

den.aspects = {
dns = {
nixos.services.resolved.enable = true;
darwin.networking.dns = [ "1.1.1.1" ];
includes = [ ./dns ];
};
};

Den auto-generates den.aspects entries from den.hosts, den.homes, and den.users. For every declared host/home/user, an aspect is created with the appropriate class configurations. You do not need to declare den.aspects manually unless adding shared aspects.

Type: attrsOf aspectsType

Namespaced aspect collections. Each key is a namespace name, each value is a full aspectsType. Populated by den.namespace or by merging upstream denful flake outputs.

den.ful.myns = {
some-aspect = { nixos.services.foo.enable = true; };
};

Type: attrsOf raw

Raw flake output for publishing namespaces. Set automatically by den.namespace; consumed by downstream flakes that import your aspects.

An aspect is an attribute set with:

KeyPurpose
<class>Config merged into hosts/homes of that class
includesList of modules or functions dispatched by context
__functorAuto-generated by parametric; drives dispatch

Functions in includes receiving { class, aspect-chain } are static — evaluated once during aspect resolution. Functions receiving context arguments ({ host }, { user }, etc.) are parametric — evaluated per context during ctxApply.

An aspect can declare a subtree adapter that controls how its includes are resolved. The adapter composes with the inherited adapter from parent aspects or context nodes.

den.aspects.monitoring = {
meta.adapter = inherited:
den.lib.aspects.adapters.filter (a: a.name != "noisy-exporter") inherited;
includes = [
den.aspects.prometheus
den.aspects.noisy-exporter # filtered out
den.aspects.grafana
];
};

The adapter receives the inherited adapter and returns a new one. This enables composition — a parent’s filter cannot be overridden by children.

Adapters set on context nodes (den.ctx.host.meta.adapter) apply transitively to all aspects resolved within that context:

# Exclude "debug-tools" from all host resolution
den.ctx.host.meta.adapter = inherited:
den.lib.aspects.adapters.filter (a: a.name != "debug-tools") inherited;

Tracks the structural origin of an aspect as a path. Top-level aspects have meta.provider = []. An aspect provided by foo (via foo.provides.bar or foo._.bar) has meta.provider = ["foo"]. Deeply nested providers accumulate: foo._.bar._.baz has meta.provider = ["foo" "bar"].

Adapters can use this to distinguish aspects by origin:

# Only include aspects provided by "monitoring"
meta.adapter = inherited:
den.lib.aspects.adapters.filter
(a: lib.take 1 (a.meta.provider or []) == ["monitoring"])
inherited;

This is the place for Den built-in batteries, reusable aspects that serve as basic utilities and examples.

See Batteries Reference.

Entities (hosts, users, homes) expose .resolved — the aspect produced by their context pipeline. Forwards can use this to pull configuration from one entity into another without manually wiring context calls.

When den._.forward is called without fromAspect, it defaults to item.resolved, resolving the source entity through its own context pipeline:

# Collect SSH host keys from all other hosts
den.aspects.iceberg.includes = [
({ host }:
den._.forward {
each = lib.filter (h: h != host) (lib.attrValues den.hosts.${host.system});
fromClass = _: "ssh-host-key";
intoClass = _: host.class; # "nixos" or "darwin"
intoPath = _: [ ];
}
)
];

Each host in each is resolved via its .resolved attribute, and the ssh-host-key class content is forwarded into the target’s OS config. host.class is the OS class name ("nixos", "darwin"), not the context type.

When aspects are resolved for a host, Den:

  1. Collects all aspects referenced by the host
  2. Extracts the class-specific config (e.g., nixos for NixOS hosts)
  3. Evaluates static includes with { class, aspect-chain }
  4. Builds context pairs from den.ctx
  5. Applies parametric includes via ctxApply
  6. Merges everything into the host’s evalModules call
Contribute Community Sponsor