I tend to write a lot, so I hope not to be repeating myself or others. The original Dendritic discourse post (linked in opening post) has links to resources and people talking about the benefits.
Dendritic uses regular nix modules, because at the end, it is just about merging modules as shown by the example of this post (which uses evalModules). If by “regular”/“normal” you mean, the way we see nix configuration examples in the wild, I’d say:
-
Most examples look monolithic. This has always been funny to me, many many nix examples I have seen since I started using nix, frequently show a huge
flake.nixfile, or at least assume you are editing a hugeflake.nix. And it is like ifnodejspeople suggested to use inlined huge js program in the package.json file itself. IMHO flake.nix should be used as an inputs manifest and the outputs function should import as soon as possible. In the dendritic pattern, you tend to use flake.nix as just a manifest, because it is only used to define inputs and immediatly importing all of./modulesfiles. This is the reason why the non-flakes example has exactly the same structure as a flakes-enabled dendritic setup: in the non-flake version the inputs manifest is just not flake.nix (just like you can use different js package managers, you can useflakes,npins, orunflakeand your configuration remains the same as shown by our non-flakes example) -
Semantic meaning. Nix files just contain a single nix expression. A file could be a boolean, an string, an array or any other nix expression. Because of this, importing a nix file requires you to know what kind of expression it contains. is it a function expected to be called? is it an array of strings representing systems?. Is the meaning of that function a package ? or is it a nixos module ?. In dendritic, all files have the same semantic meaning. They are all a nix module. (either an attribute-set or a function to attribute-set). Because of this, we can merge all files (read more about this on my article on the first link).
So you don’t have to worry about what a file means, they are all modules, internally each module can define packages, apps, or can define nixos or home configuration sub-modules. but the top-level expression is always a module.
This is where flake-parts entered the scene. A flake-parts module allows you to define perSystem packages, shells, or any amount of flake.modules.<class> internally. And I believe this is why the pattern was discovered on flake-parts. Each file (top-level module) adds something to the flake (or your configuration to avoid limiting ourselves to flakes)
For me, the main benefit is flipping-the-configuration-matrix (second link on this reply): that any file can enhance any modules.* configuration. People can organize files semantically by what each of these files contributes to the system (or parts of the system), not by where features are applied.
Each of these top-level modules (either flake-parts module or non-flake-parts modules like the ones shown in the example) can contribute to several configuration sub-modules modules.* (to enhance diverse nix configuration classes), contributing to OS-level, home-level, editor-level configurations.
These partial (deferred) modules get at the end merged by the nix module system itself from the many modules.* definitions they have, and the additive result of that is used as a single module in nixos/home configurations. The OP example is trivial, as it defines all modules in the same file but the real advantage is when many files contribute to the same aspect.
Of course we have many options/frameworks/libs to organize nix configurations, this is a good thing because the most important thing about a configuration-organization is that it suits well your mental model.
Many frameworks impose a defined structure, kinda what rails did originally, to aid people with organization. Most of the time, these organizations are defined by the meaning of the expression contained in files. You see for example directories for packages, other directory for nixos-configurations, others for home-configurations, others for nixvim-configurations. The Dendritic proposal is not to do that, do not impose any naming restriction and do not impose what nix-configuration-classes the framework supports. Each dendritic module can configure any nix configuration classes.
In the end, it is about merging (the job of the evalModules system) many tiny deferred modules contributed by many files into a single final nix/home configuration.
So, the benefit is more how you model things in your mind, how you organize and name things instead of purely technical (how stuff is built).
hope that helps.