Aspects & Functors
What is an aspect?
Section titled “What is an aspect?”An aspect is a composable unit of configuration that bundles modules
for one or more Nix classes (nixos, darwin, homeManager, or custom)
in a single attrset. Aspects declare what behavior applies — one
concern, all platforms. They compose via includes (DAG edges) and
nest: any key that is not a class or structural key is itself an aspect.
den.aspects.gaming = { host, user }: { nixos = { pkgs, ... }: { programs.steam.enable = true; }; homeManager = { pkgs, ... }: { programs.mangohud.enable = true; }; includes = [ den.aspects.performance ];};The __functor Pattern
Section titled “The __functor Pattern”Any Nix attrset with __functor can be called as a function:
let counter = { value = 42; __functor = self: n: self.value + n; };in counter 8 # => 50The __functor receives self (the attrset itself) and returns a function.
Aspects as Functors
Section titled “Aspects as Functors”Every aspect in Den has a default __functor that inspects context
parameters to decide what to produce. Bare attrsets and functions work
directly — den.lib.parametric is no longer needed:
# Bare functions work directly — no wrapper required{ nixos.foo = 1; includes = [ ({ host }: { nixos.networking.hostName = host.hostName; }) ({ user }: { homeManager.home.username = user.userName; }) ];}Aspect Structure
Section titled “Aspect Structure”Aspects have three kinds of attributes:
Owned Configurations
Section titled “Owned Configurations”Direct settings per Nix class:
den.aspects.igloo = { nixos.networking.hostName = "igloo"; darwin.nix-homebrew.enable = true; homeManager.programs.vim.enable = true;};Includes
Section titled “Includes”A list forming a dependency graph:
den.aspects.igloo.includes = [ # Static: applied unconditionally { nixos.programs.vim.enable = true; }
# Parametric: applied when context matches argument shape ({ host, ... }: { nixos.time.timeZone = "UTC"; })
# Reference to another aspect den.aspects.tools];Nested aspects
Section titled “Nested aspects”Any key on an aspect that is not a class key (nixos, homeManager, …) or a
structural key (includes, meta, …) is itself an aspect, reachable as
den.aspects.<aspect>.<name>. Names are yours to choose and nest to any
depth. In the example below, igloo is a host name and gpu is a name
chosen for the nested aspect; neither is API:
den.aspects.igloo.gpu = { host, ... }: lib.optionalAttrs (host ? gpu) { nixos.hardware.nvidia.enable = true; };A nested aspect is not applied just because its parent is. It has to be included; see Naming and inclusion.
host.gpu is not built in. host is the host’s entity record, and gpu
is an attribute you put there yourself, either as a free-form attribute on
the host declaration:
den.hosts.x86_64-linux.igloo.gpu = "nvidia";or as a typed option on every host through the host schema:
den.schema.host = { lib, ... }: { options.gpu = lib.mkOption { type = lib.types.nullOr lib.types.str; default = null; };};With the schema option every host has gpu, so test host.gpu != null
rather than host ? gpu. See
Freeform attributes.
Older configurations nest under provides (alias _), as in
den.aspects.<aspect>.provides.<name>. That spelling still evaluates to the
same aspect, but it is legacy; write the direct form.
Resolution
Section titled “Resolution”Aspects are resolved for a specific class using the den.lib.aspects.resolve API.
module = den.lib.aspects.resolve "nixos" den.aspects.igloo;Resolution collects all nixos attrs from owned configs, walks includes
recursively, applies parametric dispatch, deduplicates, and produces a
single deferredModule containing all NixOS configuration.
See also
Section titled “See also”- Configure Aspects — practical guide to owned configs, includes, nesting
- Parametric Aspects — context-aware dispatch via argument introspection
- Resolution Pipeline — how aspects feed into the full pipeline
- den.aspects reference — full option documentation