Skip to content
den

Context-aware Aspect-oriented Nix

One aspect. Every platform. NixOS, Darwin, home-manager — composed, not duplicated.

Den takes the Dendritic pattern to a whole new level, and I cannot imagine going back.
@adda - Very early Den adopter after using Dendritic flake-parts and Unify. [repo]

I’m super impressed with den so far, I’m excited to try out some new patterns that Unify couldn’t easily do.
@quasigod - Author of Unify dendritic-framework, on adopting Den. [repo]

Massive work you did here!
@drupol - Author of "Flipping the Configuration Matrix" Dendritic blog post.

Thanks for the awesome library and the support for non-flakes... it’s positively brilliant!. I really hope this gets wider adoption.
@vczf - At #den-lib:matrix.org channel.

Den is a playground for some very advanced concepts. I’m convinced that some of its ideas will play a role in future Nix areas. In my opinion there are some raw diamonds in Den.
@Doc-Steve - Author of Dendritic Design Guide

Traditional Nix configurations are host-first. Bluetooth on three machines means three files with duplicated config — one per host, split again across NixOS and home-manager.

# Without Den — duplicated across hosts and module systems
hosts/laptop/configuration.nix# hardware.bluetooth.enable = true
hosts/laptop/home.nix# services.blueman-applet.enable = true
hosts/desktop/configuration.nix# hardware.bluetooth.enable = true (again)
hosts/mac/darwin.nix# homebrew.casks = [ "blueutil" ] (different syntax)

Den inverts this: aspects are the primary unit. One aspect, all platforms.

# With Den — one aspect configures everything
den.aspects.bluetooth= {
nixos.hardware.bluetooth.enable=true;
homeManager.services.blueman-applet.enable=true;
darwin.homebrew.casks=["blueutil"];
};
# Every host that includes it gets bluetooth — across all classes
den.aspects.laptop.includes=[den.aspects.bluetooth];
den.aspects.desktop.includes=[den.aspects.bluetooth];

Den context args flow automatically — no wrappers, no specialArgs, no infinite recursion:

# Den args and NixOS module args coexist in a single function
den.aspects.laptop.nixos= { host,config,pkgs,... }: {
networking.hostName=host.name;
};

Den is a library for composing Nix configurations via aspect-oriented programming and a framework for NixOS/Darwin/home-manager built on top.

Under the hood, Den uses a pure algebraic effects pipeline — aspects compile to computations, handlers decide what to do, and a trampoline interprets the result. This gives you extensible policies for entity topology, diagrams of your resolution graph, and custom classes for any Nix module system.

graph LR
 H["host stage {host}"] --> U["user stage {host, user} (for each user)"]
 U --> HM["aspect provides homeManager/home class"]
 H --> OS["aspect provides nixos/darwin class"]
flowchart BT
 subgraph "**den.aspects.dev-tools**"
 n["nixos"]
 h["homeManager"]
 d["darwin"]
 end
 n --> server["server (NixOS)"]
 n --> laptop["laptop (NixOS)"]
 d --> mac["mac (Darwin)"]
 h --> laptop
 h --> mac
 h --> standalone["alice (standalone HM)"]

Aspect-Oriented

Aspects bundle NixOS, Darwin, home-manager, or custom class config in one composable unit. Includes form a DAG. Provides create sub-aspects. One concern, all platforms.

Pure Effects Pipeline

Built on algebraic effects via nix-effects. Aspects compile to computations, handlers own resolution strategy. Policies drive entity topology and bind behavior. Everything is extensible.

No Lock-in

Works with flake-parts, without flake-parts, or without flakes at all. Den works with anything configurable through Nix modules — NixOS, Terraform, NixVim, or your own domain.

Sharable Aspects

Namespaces let you publish and consume aspect libraries across flakes or non-flakes. Diagrams visualize your resolution graph for debugging and documentation.

Built on top of den.lib, Den provides a framework with ready-made facilities for NixOS/nix-Darwin/homes configurations.

flowchart LR
 Schema["den.hosts / den.homes"] --> Pipeline["den.policies pipeline"]
 Aspects["den.aspects"] --> Pipeline
 Batteries["den.batteries"] --> Pipeline
 Pipeline --> Resolve["Resolution"]
 Resolve --> Out["nixos / darwin / homeConfigurations"]
  1. Schemaden.hosts and den.homes declare machines, users, and their properties with den.schema modules and extensible freeform types.
  2. Aspectsden.aspects.* bundles per-class configs (nixos, darwin, homeManager, or any custom class) with .includes and .provides forming a DAG.
  3. Resolution pipelineden.policies fan out from entity kinds ({host}{host, user}, {home}) and bind behavior. Batteries register derived entity kinds like hm-host, hm-user, wsl-host.
  4. Resolution — Context-aware dispatch: functions receive entity data automatically based on their argument shape. Class modules can access both Den context and NixOS module args in a single function.
  5. Output — Each host/home is instantiated via nixpkgs.lib.nixosSystem, darwin.lib.darwinSystem, or home-manager.lib.homeManagerConfiguration.
Learn More Extensibility Example: MicroVM

Den is made possible by amazing people

Section titled "Den is made possible by amazing people"

Star History Chart

Contribute Community Sponsor

AltStyle によって変換されたページ (->オリジナル) /