Skip to content

Forward Across Classes

forward resolves an aspect for one class and injects the result into a submodule path of another class. This enables cross-class configuration routing.

The canonical use case: forward homeManager modules into nixos.home-manager.users.<name>.

forward {
each = [ items ]; # list of items to iterate over
fromClass = item: "sourceClass"; # class to resolve from
intoClass = item: "targetClass"; # class to inject into
intoPath = item: [ "path" ]; # submodule path in targetClass
fromAspect = item: aspect; # aspect to resolve
}
ParameterSignaturePurpose
eachlistOf anyItems to iterate. One forward per item.
fromClassitem → stringSource class name to resolve
intoClassitem → stringTarget class name to inject into
intoPathitem → listOf stringAttribute path for the submodule in target
fromAspectitem → aspectThe aspect to resolve for fromClass

forward returns { includes = [ ... ]; } — an aspect with one include per item. Each include:

  1. Resolves fromAspect item for fromClass item
  2. Wraps the resolved module as { imports = [ module ]; } at intoPath item
  3. Places the result under intoClass item
flake.aspects = { aspects, ... }: {
my-host = {
targetClass = {
imports = [ targetSubmodule ];
targetMod.names = [ "from-target" ];
};
sourceClass.names = [ "from-source" ];
includes = [
({ class, aspect-chain }: forward {
each = [ "source" ];
fromClass = item: "${item}Class";
intoClass = _: "targetClass";
intoPath = _: [ "targetMod" ];
fromAspect = _: lib.head aspect-chain;
})
];
};
};

Resolving for "targetClass" merges ["from-target", "from-source"].

This is how Den forwards user home-manager configs into host NixOS:

hmSupport = { host }: forward {
each = host.users;
fromClass = _user: "homeManager";
intoClass = _user: "nixos";
intoPath = user: [ "home-manager" "users" user.userName ];
fromAspect = user: den.aspects.${user.userName};
};

Each user’s homeManager aspect gets resolved and placed at nixos.home-manager.users.<name>.

Contribute Community Sponsor