Skip to content

Choosing a Mechanism

den has several ways to get configuration from where you write it to where it applies. They overlap on purpose, which makes the first question “which one do I use?”. This page answers it by goal.

I want to…UseGuide
bundle aspects so one brings the othersincludes = [ … ] on the aspectConfigure Aspects
configure one module system (NixOS, darwin, home-manager)a class key: nixos, darwin, homeManager, …Class Modules
vary config by host or usera class module taking { host, ... }, or an aspect that is a function of { host, ... }Parametric Aspects
apply an aspect to every host / user / homeden.schema.<kind>.includes, or den.default.includes for allSchema reference
give an aspect per-host tunablesthe settings pattern (a reserved settings key)Aspect Settings
attach an aspect to entities by a rule (“every server gets X”)a policy returning policy.includePolicies
include something only when other aspects are presentpolicy.when with hasAspectden.aspects reference
create entities (users on a host, hosts in an environment)a policy returning policy.resolve.toPolicy reference
send config from a host to its users, or from a user to its hostsee Where Does My Config Land?Mutual Config
change the host from a user aspectthe user class for the user’s own account; provides.<host> or provides.to-hosts for anything else, never untargeted nixos (#694)Where Does My Config Land?
write a new class that lands inside another (user → users.users.<name>)den.classes.<name> plus a policy.route policyCustom Nix Classes
share data (ports, addresses, extension lists) rather than modulesa quirk, plus pipes if it must cross scopesQuirks & Pipes
offer optional parts of an aspect for others to picknested aspects, den.aspects.<aspect>.<name>Configure Aspects
stop an aspect or policy from applying in a subtreeexcludesPolicy reference

Both deliver config from a host to its users. provides.to-users lives inside the aspect that holds the behaviour; a policy lives beside it.

# provides: the relationship is written inside the behaviour
den.aspects.igloo.provides.to-users.homeManager.programs.git.enable = true;
# policy: the behaviour is a plain aspect, the relationship is a rule
den.aspects.git.homeManager.programs.git.enable = true;
den.policies.git-for-igloo-users = { host, user, ... }:
lib.optional (host.name == "igloo") (den.lib.policy.include den.aspects.git);
den.schema.user.includes = [ den.policies.git-for-igloo-users ];

provides is shorter and stays supported. For new configurations prefer the policy: the git aspect stays reusable anywhere, and “who gets it” is visible as a rule instead of buried in one host’s aspect.

Both move a custom class’s content into another class. forward is the older battery with more options in one call; policy.route is the policy effect it is built from. Den’s own os, user and wsl classes use route. Reach for route in new code and for forward when you need one of its extras (per-item each, adapter modules) in a single expression.

A class key carries modules into one module system. A quirk carries data (records, lists, packages) that any aspect can read and turn into config for whatever module system it writes. If the thing you are sharing is “open port 443”, that is data: a quirk lets the firewall aspect, a monitoring aspect and a reverse proxy all read it. If it is “set services.nginx.enable”, that is a module: use nixos.

flowchart TD
  Q1{"Is it NixOS / darwin / home-manager config?"}
  Q1 -- "no, it's data others read" --> QK["quirk (+ pipes to cross scopes)"]
  Q1 -- yes --> Q2{"Does it depend on which host or user?"}
  Q2 -- yes --> PA["class module taking host / user, or a parametric aspect"]
  Q2 -- no --> Q3{"Who should get it?"}
  PA --> Q3
  Q3 -- "one aspect's users" --> INC["includes"]
  Q3 -- "every entity of a kind" --> SCH["den.schema.kind.includes / den.default"]
  Q3 -- "entities matching a rule" --> POL["policy + policy.include"]
  Q3 -- "only if other aspects are present" --> WHEN["policy.when + hasAspect"]
  Q3 -- "the other side: host to users, user to host" --> WHERE["see Where Does My Config Land?"]
ContributeCommunitySponsor