Modular, context-aware and aspect-oriented dendritic Nix configurations. Discussions: https://oeiuwq.zulipchat.com/join/nqp26cd4kngon6mo3ncgnuap/ den.oeiuwq.com
configurations den dendritic nix aspect oriented
10
fork

Configure Feed

Select the types of activity you want to include in your feed.

Nix 60.3%
MDX 33.2%
Astro 5.0%
JavaScript 1.1%
Just 0.2%
CSS 0.1%
TypeScript 0.1%
373 1 12

Clone this repository

https://tangled.org/oeiuwq.com/den https://tangled.org/did:plc:hwcqoy35x55nzde2sm6dbvq7/den
git@tangled.org:oeiuwq.com/den git@tangled.org:did:plc:hwcqoy35x55nzde2sm6dbvq7/den

For self-hosted knots, clone URLs may differ based on your setup.

Download tar.gz
README.md

Sponsor Vic Ask DeepWiki Dendritic Nix License CI Status

den - Aspect-oriented context-driven Dendritic Nix configurations.#

den and vic's dendritic libs made for you with Love++ and AI--. If you like my work, consider sponsoring

At its core, Den is a library built on flake-aspects for activating configuration-aspects via context-transformation pipelines.

On top of the library, Den provides a framework for the NixOS/nix-Darwin/Home-Manager Nix domains.

Den embraces your Nix choices and does not impose itself. All parts of Den are optional and replaceable. Works with your current setup, with/without flakes, flake-parts or any other Nix module system.

Templates:#

default: +flake-file +flake-parts +home-manager

minimal: +flakes -flake-parts -home-manager

noflake: -flakes +npins +lib.evalModules +nix-maid

microvm: MicroVM runnable-pkg and guests. custom ctx-pipeline.

example: cross-platform

ci: Each feature tested as code examples

bogus: Isolated test for bug reproduction

Examples:#

Want yours featured? send me a DM via matrix or zulip (links at GH Discussions)

vic/vix: author spends more time in Den itself (-flakes)

quasigod.xyz: Beautiful organization, uses custom Den namespaces and Den angle brackets (+flake-parts)

Adda: A comprehensive system configuration for multiple hosts (+flake-parts +flake-file +home-manager +files)

GitHub Search: Growing community adoption, 976+ results and counting.

❄️ Try it:

# Run virtio MicroVM from templates/microvm
nix run github:vic/den?dir=templates/microvm#runnable-microvm
# Run qemu VM from templates/example
nix run github:vic/den

Testimonials#

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.

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.

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

Den Versioning - v0.x is moving fast#

Den main always requires flake-aspects main. Same for latest versions.

# Bleeding edge Den
{
  inputs.den.url = "github:vic/den";
  inputs.flake-aspects.url = "github:vic/flake-aspects";
}

main branch follows development, this is where PRs are merged, it is stable in the sense that every PR checks CI. However, some PR might introduce changes that require you being aware of what is happening in Den. For people tracking development, we have announcements tagged heads-up whenever this happens.

# Released Den - no longer gets updates until next release
{
  inputs.den.url = "github:vic/den/latest";
  inputs.flake-aspects.url = "github:vic/flake-aspects/latest";
}

latest tag always follows the latest created tag. This is intended for people that wishes to wait for a release and reading all announcements at release notes. if you flake update, you will only move between release points.

Diff of changes since latest release: latest...main

For other than main and latest versions, each release-notes documents the particular flake-aspects version needed by Den. This is because flake-aspects can be used independently of Den, and it does not follows Den version numbers because it is not as fast-paced as Den.

Code example (OS configuration domain)#

Defining hosts, users and homes.#

den.hosts.x86_64-linux.lap.users.vic = {};
den.hosts.aarch64-darwin.mac.users.vic = {};
den.homes.aarch64-darwin.vic = {};
$ nixos-rebuild switch --flake .#lap
$ darwin-rebuild switch --flake .#mac
$ home-manager   switch --flake .#vic

Extensible Schemas for hosts, users and homes.#

# extensible base modules for common, typed schemas
den.schema.user = { user, lib, ... }: {
  config.classes =
    if user.userName == "vic" then [ "hjem" "maid" ]
    else lib.mkDefault [ "homeManager" ];

  options.mainGroup = lib.mkOption { default = user.userName; };
};

Dendritic Multi-Platform Hosts#

# modules/my-laptop.nix
{ den, inputs, ... }: {
  den.aspects.my-laptop = {
    # re-usable configuration aspects. Den batteries and yours.
    includes = [ den.provides.hostname den.aspects.work-vpn ];

    # regular nixos/darwin modules or any other Nix class
    nixos  = { pkgs, ... }: { imports = [ inputs.disko.nixosModules.disko ]; };
    darwin = { pkgs, ... }: { imports = [ inputs.nix-homebrew.darwinModules.nix-homebrew ]; };

    # Custom Nix classes. `os` applies to both nixos and darwin. contributed by @Risa-G.
    # See https://den.oeiuwq.com/guides/custom-classes/#user-contributed-examples
    os = { pkgs, ... }: {
      environment.systemPackages = [ pkgs.direnv ];
    };

    # host can contribute default home environments to all its users.
    homeManager.programs.vim.enable = true;
  };
}

Multiple User Home Environments#

# modules/vic.nix
{ den, ... }: {
  den.aspects.vic = {
    # supports multiple home environments, eg: for migrating from homeManager.
    homeManager = { pkgs, ... }: { };
    hjem.files.".envrc".text = "use flake ~/hk/home";
    maid.kconfig.settings.kwinrc.Desktops.Number = 3;

    # user can contribute OS-configurations to any host it lives on
    darwin.services.karabiner-elements.enable = true;

    # user class forwards into {nixos/darwin}.users.users.<userName>
    user = { pkgs, ... }: {
      packages = [ pkgs.helix ];
      description = "oeiuwq";
    };

    includes = [
      den.provides.primary-user        # re-usable batteries
      (den.provides.user-shell "fish") # parametric aspects
      den.aspects.tiling-wm            # your own aspects
      den.aspects.gaming.provides.emulators
    ];
  };
}

Custom Dendritic Nix Classes#

Custom classes is how Den implements homeManager, hjem, wsl, microvm support. You can use the very same mechanism to create your own classes.

# Example: A class for role-based configuration between users and hosts

roleClass =
  { host, user }:
  { class, aspect-chain }:
  den._.forward {
    each = lib.intersectLists (host.roles or []) (user.roles or []);
    fromClass = lib.id;
    intoClass = _: host.class;
    intoPath = _: [ ];
    fromAspect = _: lib.head aspect-chain;
  };

den.ctx.user.includes = [ roleClass ];

den.hosts.x86_64-linux.igloo = {
  roles = [ "devops" "gaming" ];
  users = {
    alice.roles = [ "gaming" ];
    bob.roles = [ "devops" ];
  };
};

den.aspects.alice = {
  # enabled when both support gaming role
  gaming = { pkgs, ... }: { programs.steam.enable = true; };
};

den.aspects.bob = {
  # enabled when both support devops role
  devops = { pkgs, ... }: { virtualisation.podman.enable = true; };

  # not enabled at igloo host (bob missing gaming role on that host)
  gaming = {};
};

Guarded Forwarding Classes#

Forward guards allow feature-detection without mkIf/mkMerge cluttering.

Aspects can simply assign configurations into a class (here persys) from any file, without any mkIf/mkMerge cluttering. The logic for determining if the class takes effect is defined at a single place.

Example inspired by @Doc-Steve

# Aspects use the `persys` class without any conditional. And guard guarantees
# settings are applied **only** when impermanence module has been imported.
persys = { host }: den._.forward {
  each = lib.singleton true;
  fromClass = _: "persys";
  intoClass = _: host.class;
  intoPath = _: [ "environment" "persistance" "/nix/persist/system" ];
  fromAspect = _: den.aspects.${host.aspect};
  guard = { options, config, ... }: options ? environment.persistance;
};

# enable on all hosts
den.ctx.host.includes = [ persys ];

# aspects just attach config to custom class
den.aspects.my-laptop.persys.hideMounts = true;

User-defined Extensions to Den Framework.#

See example template/microvm for an example of custom den.ctx and den.schema extensions for supporting Declarative MicroVM guests with automatic host-shared /nix/store.

den.hosts.x86_64-linux.guest = {};
den.hosts.x86_64-linux.host = {
  microvm.guests = [ den.hosts.x86_64-linux.guest ];
};

den.aspects.guest = {
  # propagated into host.nixos.microvm.vms.<name>;
  microvm.autostart = true;

  # guest supports all Den features.
  includes = [ den.provides.hostname ];
  # As MicroVM guest propagated into host.nixos.microvm.vms.<name>.config;
  nixos = { pkgs, ... }: { environment.systemPackages = [ pkgs.hello ]; };
};