You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: dev/book/src/Dendritic.md
+58-18Lines changed: 58 additions & 18 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -5,35 +5,41 @@
5
5
We say that Dendritic nix configurations are _aspect-oriented_, meaning that each nix file
6
6
provides config-values for the same _aspect_ across different nix configuration classes.
7
7
8
-
This is done via flake-parts' `flake.modules.<class>.<aspect>` options.
8
+
Normally, this is done via flake-parts' `flake.modules.<class>.<aspect>` options.
9
9
10
10
Where `<class>` is a type of configuration, like [`nixos`](https://nixos.org/manual/nixos/stable/options), [`darwin`](https://nix-darwin.github.io/nix-darwin/manual/), [`homeManager`](https://home-manager.dev/manual/23.11/options.xhtml), [`nixvim`](https://nix-community.github.io/nixvim/search/), etc.
11
11
12
12
And `<aspect>` is the _cross-cutting concern_ or _feature_ that is being configured across
13
13
one or more of these classes.
14
14
15
+
> [!NOTE]
16
+
> Dendritic is a configuration *pattern* - a way-of-doing-. Not a library nor a framework.
17
+
> See [No Dependencies](#no-dependencies).
18
+
15
19
### Example of a dendritic configuration.
16
20
17
21
As an example of what a dendritic nix config looks like, suppose we want to configure ssh facilities
18
22
(the `ssh` aspect) across our NixOS, Nix-darwin hosts and user homes.
19
23
20
24
```nix
21
25
# modules/ssh.nix -- like every other file inside modules, this is a flake-parts module.
22
-
{ config, ... }: {
26
+
{ inputs, config, ... }: let
27
+
scpPort = 2277; # let-bindings or custom flake-parts options communicate values across classes
28
+
in {
23
29
flake.modules.nixos.ssh = {
24
-
# Linux config: server, firewall-ports, etc.
30
+
# Linux config: setup OpenSSH server, firewall-ports, etc.
25
31
};
26
32
27
33
flake.modules.darwin.ssh = {
28
-
# MacOS config: enable builtin ssh server, etc.
34
+
# MacOS config: enable MacOS builtin ssh server, etc.
29
35
};
30
36
31
37
flake.modules.homeManager.ssh = {
32
-
# setup ~/.ssh/config or keys.
38
+
# setup ~/.ssh/config, authorized_keys, private keys secrets, etc.
33
39
};
34
40
35
41
perSystem = {pkgs, ...}: {
36
-
# expose custom package/checks/devshells by this aspect.
42
+
# custom packages taking advantage of ssh facilities, eg deployment-scripts.
37
43
};
38
44
}
39
45
```
@@ -62,7 +68,7 @@ in
62
68
};
63
69
64
70
flake.modules.darwin.${userName} = {
65
-
system.primaryUser = userName; # configuring a user is different on MacOS than on NixOS.
71
+
system.primaryUser = userName; # note that configuring a user is different on MacOS than on NixOS.
66
72
};
67
73
68
74
flake.modules.homeManager.${userName} =
@@ -100,7 +106,7 @@ All files being flake-parts modules, means we have no need for manually importin
100
106
loaded at once into a single import.
101
107
102
108
The Dendritic community commonly uses [`vic/import-tree`](https://github.com/vic/import-tree) for this.
103
-
Note: import-tree ignores any file that has an `_` anywhere as part of its path.
109
+
Note: import-tree ignores any file that has an `/_` as part of its path.
104
110
105
111
```nix
106
112
# flake.nix
@@ -123,9 +129,9 @@ This means we can have:
123
129
Instead of having huge `flake.nix` files with lots of nix logic inside. It is now possible
124
130
to move all nix logic into well organized auto-imported flake-parts in `./modules`. This way, `flake.nix` serves more as a manifest of dependencies and flake entrypoint.
125
131
126
-
Some people go a step further and use [vic/flake-file](https://github.com/vic/flake-file) to manage their flake.nix automatically, by letting each flake-part module also define the flake inputs needed by each module.
132
+
Some people go a step further and use [`vic/flake-file`](https://github.com/vic/flake-file) to manage their flake.nix automatically, by letting each flake-parts module also define the flake inputs needed by each module.
127
133
128
-
Any flake-parts module can contribute to flake.nix as needed, either inputs/flake-configuration (by using `vic/flake-file`) or outputs (modules/packages/checks/osConfigurations/etc).
134
+
Any flake-parts module contributes to flake.nix as needed, either inputs/flake-configuration (by using `vic/flake-file`) or outputs (modules/packages/checks/osConfigurations/etc by using flake-parts options).
129
135
130
136
```nix
131
137
# ./modules/home/vim.nix
@@ -140,15 +146,17 @@ Any flake-parts module can contribute to flake.nix as needed, either inputs/flak
140
146
141
147
### Feature Centric instead of Host Centric.
142
148
143
-
As noted by Pol Dellaiera in [Flipping the Configuration Matrix](https://not-a-number.io/2025/refactoring-my-infrastructure-as-code-configurations/#flipping-the-configuration-matrix):
149
+
As noted by Pol Dellaiera in [Flipping the Configuration Matrix](https://not-a-number.io/2025/refactoring-my-infrastructure-as-code-configurations/#flipping-the-configuration-matrix) -a very recommended read-:
144
150
145
-
> the configuration is now structured around features, not hostnames. It is a shift in the axis of composition, essentially an inversion of configuration control. What may seem like a subtle change at first has profound implications for flexibility, reuse, and maintainability.
151
+
> [In a Dendritic setup]the configuration is now structured around features, not hostnames. It is a shift in the axis of composition, essentially an inversion of configuration control. What may seem like a subtle change at first has profound implications for flexibility, reuse, and maintainability.
146
152
147
153
You will notice that you start naming your files around the `aspect`s (features) they define
148
154
instead of where they are specifically applied.
149
155
156
+
It might be useful to ask yourself **_how_** you like to use your Linux Environment, instead of **_what_** components constitute the environment or **_where_** will the environment finally applied. By doing so, you will start naming your aspects around "usability concerns", eg. `macos-like-bindings`, `scrolling-desktop`, `tui` interfaces, nextgen `cli` utilities, `ai` intergation, etc. Instead of naming modules around specific packages or host-names.
157
+
150
158
In the following example, the `scrolling-desktop` aspect is included accross different operating systems:
151
-
On Linux, `flake.modules.nixos.scrolling-destop` might enable [`niri`](https://variety4me.github.io/niri_docs/) and on MacOS, `flake.modules.darwin.scrolling-desktop` might enable [`PaperWM.spoon`](https://github.com/mogenson/PaperWM.spoon).
159
+
On Linux, `flake.modules.nixos.scrolling-desktop` might enable [`niri`](https://variety4me.github.io/niri_docs/) and on MacOS, `flake.modules.darwin.scrolling-desktop` might enable [`paneru`](https://github.com/karinushka/paneru). Each configuration uses the tools available on the respective platform, but the aspect is the same, and you could use flake-parts level options or let-bindings to configure behaviour on both (e.g, the scrolling animations speed).
152
160
153
161
```nix
154
162
# ./modules/hosts.nix
@@ -165,6 +173,8 @@ On Linux, `flake.modules.nixos.scrolling-destop` might enable [`niri`](https://v
165
173
}
166
174
```
167
175
176
+
177
+
168
178
### Feature _Closures_
169
179
170
180
By closure, we mean: everything that is needed for a given _feature_ to work is
@@ -191,12 +201,42 @@ other impact than the overall capabilities provided into your systems.
191
201
This is an easy way to disable loading files while on a huge refactor. Or when some hosts
192
202
or features should be decommissioned immediately/temporarily.
193
203
194
-
### No dependencies other than flake-parts
204
+
### No dependencies
205
+
206
+
> _Dendritic_ is a configuration *pattern* - a _way-of-doing_-, not a library nor a framework.
207
+
208
+
The Dendritic repository has no code at all and any libraries mentioned on this document are mere recommendations and pointers to things other people using the Dendritic pattern has found useful.
195
209
196
-
Since the dendritic pattern builds around flake-parts modules, the only dependency is
197
-
`flake-parts`. You can load files using import-tree or any other means. You can also use
198
-
any flake-parts based library to define your configurations, like [Unify](https://codeberg.org/quasigod/unify),
199
-
as long as it exposes `flake.modules.<class>.<aspect>` attribute sets.
210
+
You are free and encouraged to explore new ways of doing or wiring Dendritic setups. Be sure to share your insights with the community.
211
+
212
+
Because all of this, there are many possible implementations of the Dendritic pattern.
213
+
214
+
Some people like to use inline-style definitions:
215
+
216
+
```nix
217
+
{ inputs, ... }:
218
+
{
219
+
flake.modules.<class1>.<aspect1> = { ... };
220
+
flake.modules.<class2>.<aspect1> = { ... };
221
+
flake.modules.<class3>.<aspect1> = { ... };
222
+
}
223
+
```
224
+
225
+
Others might prefer nested modules using libs like [unify](https://codeberg.org/quasigod/unify) or [`vic/flake-aspects`](https://github.com/vic/flake-aspects):
226
+
227
+
All is good as long as you expose `flake.modules.<class>.<aspect>` attribute sets.
0 commit comments