Sponsor Vic Ask DeepWiki Dendritic Nix License CI Status

den - an aspect-oriented approach to Dendritic Nix configurations.

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

den
  • Dendritic: same concern across different Nix classes.

  • Flake optional. Works with stable/unstable Nix and with/without flake-parts.

  • Create DRY & class-generic modules.

  • Parametric over host/home/user.

  • Context-aware dependencies: user/host contributions.

  • Share aspects across systems & repos.

  • Routable configurations.

  • Custom factories for any Nix class.

  • Use stable/unstable channels per config.

  • Freeform host/user/home schemas (no specialArgs) with base modules.

  • Multi-platform, multi-tenant hosts.

  • Batteries: Opt-in, replaceable aspects.

  • Opt-in <angle/brackets> aspect resolution.

  • Features tested.

  • Concepts documented.

Need more batteries? See vic/denful.

❄️ Try it now!

Launch our template VM:

nix run github:vic/den

Or, initialize a project:

nix flake init -t github:vic/den
nix flake update den
nix run .#vm

Real-world examples for inspiration

Available templates

  • default batteries-included layout.
  • minimal minimalistic flake.
  • noflake no flakes, no flake-parts, user nix-maid.
  • example examples.
  • ci tests for all features.
  • bogus reproduce and report bugs.

Den fundamental idea

Configurations that can be applied to multiple host+user combinations.

# context => aspect
{ host, user, ... }@context: {
  # any Nix configuration classes
  nixos = { };
  darwin = { };
  homeManager = { };
  # supports conditional includes that inspect context
  # unlike nix-module imports
  includes = [ ];
}

You first define which Hosts, Users and Homes exist using freeform-attributes or base-modules.

{
  # isWarm or any other freeform attr
  den.hosts.x86_64-linux.igloo.isWarm = true;
}

Then, you write functions from context host/user to configs.

{
  den.aspects.heating = { host, user, ... }: {
    nixos = { ... }; # depends on host.isWarm, etc.
    homeManager = { ... };
  };

  # previous aspect can be included on any host
  #   den.aspects.igloo.includes = [ den.aspects.heating ];
  # or by default in all of them
  #   den.default.includes = [ den.aspects.heating ];
}

This way, configurations are truly re-usable, as they are nothing more than functions of the particularities of the host or its users.

Code example

See schema in _types.nix.

# modules/hosts.nix
{
  # same vic home-manager aspect shared
  # on laptop, macbook and standalone-hm
  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

Any module can contribute configurations to aspects.

# modules/my-laptop.nix
{ den, inputs, ... }: {

  # Example: enhance the my-laptop aspect.
  # This can be done from any file, multiple times.
  den.aspects.my-laptop = {

    # this aspect includes configurations
    # available from other aspects
    includes = [
      # your own parametric aspects
      den.aspects.workplace-vpn
      # den's opt-in batteries includes.
      den.provides.home-manager
    ];

    # any file can contribute to this aspect, so
    # best practice is to keep concerns separated,
    # each on their own file, instead of having huge
    # modules in a single file:

    # any NixOS configuration
    nixos  = {
      # A nixos class module, see NixOS options.
      # import third-party NixOS modules
      imports = [
        inputs.disko.nixosModules.disko
      ];
      disko.devices = { /* ... */ };
    };
    # any nix-darwin configuration
    darwin = {
      # import third-party Darwin modules
      imports = [
        inputs.nix-homebrew.darwinModules.nix-homebrew
      ];
      nix-homebrew.enableRosetta = true;
    };
    # For all users of my-laptop
    homeManager.programs.vim.enable = true;

  };
}
# modules/vic.nix
{ den, ... }: {
  den.aspects.vic = {
    homeManager = { /* ... */ };
    # User contribs to host
    nixos.users.users = {
      vic.description = "oeiuwq";
    };
    includes = [
      den.aspects.tiling-wm
      den.provides.primary-user
    ];
  };
}

You are done! You know everything to start creating configurations with den.

Feel free to to explore the codebase, particularly our included batteries and tests.

Learn more at our documentation website

Join our community discussion.