den and vic's dendritic libs made for you with Love++ and AI--. If you like my work, consider sponsoring
Need more batteries? See vic/denful. Join the community discussion. Ask questions, share how you use |
🏠 Concise definitions of Hosts, Users and Standalone-Homes. See _types.nix for complete schema. # modules/hosts.nix
{
# This example defines the following aspects:
# den.aspects.my-laptop and den.aspects.vic
# standalone-hm and nixos-hm share vic aspect
# $ nixos-rebuild switch --flake .#my-laptop
den.hosts.x86-64-linux.my-laptop.users.vic = {};
# $ home-manager switch --flake .#vic
den.homes.aarch64-darwin.vic = { };
# That's it! Now lets attach configs via aspects
}🧩 Aspect-oriented configurations. (example) # modules/my-laptop.nix -- Attach behaviour to host
{ den, ... }:
{
den.aspects.my-laptop = {
# dependency graph on other shared aspects
includes = [
# my parametric { host } => aspect
den.aspects.vpn # setups firewall/daemons
# opt-in, replaceable batteries included
den.provides.home-manager
];
# provide same features at any OS/platform
nixos = ...; # (see nixos options)
darwin = ...; # (see nix-darwin options)
# contrib hm-config to all my-laptop users
homeManager.programs.vim.enable = true;
};
}
# modules/vic.nix -- Reused in OS/standalone HM
{ den, ... }:
{
den.aspects.vic = {
homeManager = ...; # (see home-manager options)
# user can contrib to hosts where it lives
nixos.users.users.vic.description = "oeiuwq";
includes = [
den.aspects.tiling-wm
# parametric { user, host } => aspect
den.provides.primary-user # vic is admin
];
};
}For real-world examples, see ❄️ Try it now! Launch our template VM: nix run github:vic/denOr clone it and run the VM as you edit nix flake init -t github:vic/den
nix flake update den
nix run .#vmOur default template provides a layout for quickstart. |
You are done! You know everything there is to know about den for creating configurations with it.
However, if you want to learn more about how it works, I have tried to document some other topics in collapsible sections to avoid distraction from the introduction.
Learn about aspects, static and parametric. Default aspects and dependencies.
Learn about aspects, static and parametric. Default aspects and dependencies.
There are two fundamental types of aspects in den, static and parametric.
# An aspect is a collection of many
# Nix configuration modules, each having
# a different `class`.
den.aspects.my-laptop = {
nixos = { };
darwin = { };
homeManager = { };
nixVim = { };
nixDroid = { };
# aspects can be nested via `provides`
# forming a tree structure.
provides.gaming = {
nixos = { };
nixDroid = { };
# aspects can also `include` others
# forming a graph of dependencies
includes = [
# gaming.nixos module will mixin
# nvidia-gpu.nixos module if any.
den.aspects.nvidia-gpu
];
};
};
|
# The convention is to always use named args.
# These required args is the **context** the
# aspect needs to provide configuration.
hostParametric = { host }: {
nixos.networking.hostName = host.hostName;
# A parametric aspect can also ask other
# aspects for context-aware configurations.
# Here, we ask two other parametric aspects
# given the `{ host, gaming }` context.
includes = let
context.host = host;
context.gaming.emulators = [ "nes" ];
in map (f: f context) [
den.default
den.aspects.gaming-platform
];
};Den uses the following contexts by default. The aspect system is not limited to these,
|
Den has an special aspect at den.default that serves for global configuration. den.default is included by default in all Hosts, Users and Homes. For example a Home configuration invokes den.default { inherit home; }, to obtain the aggregated defaults for home contexts.
{
# you can assign static values directly.
den.default.nixos = {
system.stateVersion = "25.11";
};
# you can also include other aspects
den.default.includes = [
{ darwin.system.stateVersion = 6; }
]
}It is possible to also register context-aware parametric aspects in # This example is split to aid reading.
let
hasOneUser = host:
length (attrNames host.users) == 1;
hasUser = host: user:
hasAttr user.name host.users;
makeAdmin = user: {
nixos.users.users.${user.name} = {
extraGroups = [ "wheel" ];
};
};
# IFF host has ONE user, make it admin
single-user-is-admin = { host, user }:
if hasOneUser host && hasUser host user
then makeAdmin user else { };
in
{
den.default.includes = [
# will be called *ONLY* on when the
# `{ host, user }` context is used.
single-user-is-admin
];
}The following is the code for how { den, ... }: {
den.default.__functor = den.lib.parametric true;
}You can do the very same for other aspects of you
that can have context-aware aspects in their { den, ...}: {
den.aspects.gaming.__functor = den.lib.parametric true;
# any other file can register gaming aspects
den.aspects.gaming.include = [
({ emulation }: {
nixos = ...;
includes = [ den.aspects.steam ];
})
{ nixos = ...; } # always included
({ gpu }: { }) # non-match on my-laptop
];
# then you can depend on the gaming aspect:
den.aspects.my-laptop.includes = [
(den.aspects.gaming { emulation = "neogeo"; })
];
}For more examples on parametric aspects explore our batteries.
|
Accessing an aspect module causes Aditional to this, Host also include Also for each user, User modules are read from os-home configurations. It basically invokes A user also depends on Home just uses its own module, its includes, and invokes |
Learn about organizing patterns for reuse.
Learn about organizing patterns for reuse.
No two nix configurations are the same. We all tend to organize things as we feel better. This section will try to outline some hints on possible ways to organize aspects, none of this is mandatory, and indeed you are encouraged to explore and share your own patterns and insights.
The first principle is using .provides. (aka ._.) to nest your aspects as they make sense for you.
Unlike normal flake-parts, where modules are flat and people tend to use names like flake.modules.nixos."host/my-laptop" or nixos."feature/gaming" to avoid collission, in den you have a proper tree structure.
I (vic), use an aspect vix for all features on my system, and from there I create sub-aspects.
Because writing den.aspects.vix._.gaming._.emulation tends to be repetitive, I use the following vix alias as module argument.
This pattern is also shown in the default template, under
_profile.
NOTE:
denprovides an angle brackets experimental feature that allows even shorter syntax for deep.provide.access. See import-non-dendritic.nix for an example usage.
# modules/namespace.nix
{ config, ... }:
{
den.aspects.vix.provides = { };
_module.args.vix = # up to provides
config.den.aspects.vix.provides;
} |
# modules/my-laptop.nix
{ vix, ... }:
{
vix.gaming = {
_.steam.includes = [
vix.gpu
vix.performance-profile
];
};
} |
The following example routes configurations into the vix namespace.
This is just an example of using parametric aspects to depend on other
aspects in any part of the tree.
# modules/routes.nix
{ den, ... }:
let
noop = _: { };
by-platform-config = { host }:
vix.${host.system} or noop;
user-provides-host-config = { user, host }:
vix.${user.aspect}._.${host.aspect} or noop;
host-provides-user-config = { user, host }:
vix.${host.aspect}._.${user.aspect} or noop;
route = locator: { user, host }@ctx:
(locator ctx) ctx;
in
{
den.aspects.routes.__functor =
den.lib.parametric true;
den.aspects.routes.includes =
map route [
user-provides-host-config
host-provides-user-config
by-platform-config
];
} |
{
# for all darwin hardware
vix.aarch64-darwin = { host }: {
darwin = ...;
};
# config bound to vic user
# on my-laptop host.
vix.vic.provides.my-laptop =
{ host, user }: {
nixos = ...;
};
}Use your imagination, come up with an awesome Dendritic setup that suits you. |
You made it to the end!, thanks for reading to this point. I hope you enjoy using
denas much as I have done writing it and have put dedication on it for being high quality-nix for you. <3. I feel like den is now feature complete, and it will not likely change.
Yes, please, anything!. From fixing my bad english and typos, to sharing your ideas and experience with den in our discussion forums. Feel free to participate and be nice with everyone.
PRs are more than welcome, the CI runs some checks that verify nothing (known) is broken. Any new feature needs a test in _example/ci.nix.
If you need to run the test suite locally:
$ nix flake check ./checkmate --override-input target .
$ cd templates/default && nix flake check --override-input den ../..