Library / SDK
mightyiam/dendritic avatar
mightyiam/dendritic

dendritic is a file layout convention for Nix configurations

A Nixpkgs module system usage pattern

655 stars16 forksUnknownMIT

At a glance

What is it?
The dendritic pattern is a documented way to organise Nixpkgs module system configurations so that every file except the entry points is a module of a single top-level configuration, and it is delivered as a pattern and a set of rules rather than as a library you install.
Who is it for?
dendritic fits a Nix user who keeps more than one configuration, shares modules between them, and has re-architected the same tree more than once, because the pattern removes the question of what a given file is and lets paths carry feature names. It does not fit a single-machine configuration that fits in one file, and it is not a tool, so there is nothing to install and no upgrade path to think about.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 49 days ago.
What is it written in?
GitHub does not report a main language for this repository.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A pattern, not a package

The dendritic pattern is described in one line as a Nixpkgs module system usage pattern, and the repository reflects that: the top level holds a LICENSE, a README.md and a logo.jpg. There is no code to install, no package to pin and no release to track.

What it is instead is a convention with a rationale, and the rationale is stated in the background section. NixOS, home-manager and nix-darwin are popular projects that let a user produce derivations customised by evaluating a Nixpkgs module system configuration. The document says that figuring out a practical and expressive architecture for a codebase that provides configurations had proven to cost many a Nix user numerous rounds of re-architecturing.

The factors it blames for that complexity are worth listing, because they are the actual problem the pattern solves: multiple configurations, sharing of modules across configurations, multiple configuration classes such as nixos and home-manager, configuration nesting such as home-manager within NixOS or within nix-darwin, cross-cutting concerns that span multiple configuration classes, and accessing values such as functions, constants and packages across files.

That last item is the one that usually bites. In most layouts, a value defined in one file has to be fetched by a path lookup or passed by hand, and the wiring becomes a property of the directory structure rather than of the code.

One top-level configuration, and the rule for every other file

The pattern reconciles those factors with another application of the Nixpkgs module system, a top-level configuration. That top-level configuration facilitates the declaration and evaluation of lower-level configurations such as NixOS, home-manager and nix-darwin.

It is commonly a flake-parts configuration, but the document is careful to say it does not have to be, that alternatives to flake-parts may exist, and that the module system can also be used directly through lib.evalModules.

The central rule follows. In the dendritic pattern every Nix file except for entry points such as default.nix and flake.nix is a module of the top-level configuration. In other words, every Nix file that is not an entry point is a Nixpkgs module system module imported directly into the evaluation of the top-level configuration.

On top of that, every top-level module implements a single feature, does so across all configurations that the feature applies to, and sits at a path that serves to name that feature. Three constraints, and they are the pattern in miniature: one feature per file, the feature applied wherever it is relevant, and the directory name doing the labelling.

Lower-level modules and configurations such as NixOS, home-manager and nix-darwin are then stored as option values in the top-level configuration, and those lower-level modules take part in the evaluation of any number of lower-level configurations.

deferredModule and the value merging that makes it work

The mechanism that lets many lower-level modules coexist under one name is the deferredModule type and similar implementations, which feature value merging. That allows multiple lower-level module values to merge under one distinct name.

A lower-level module can be declared directly, under a name of its own:

nix
# modules/audio.nix
nixos.modules.audio = { /* content */ };

Or it can be merged with others under a common name:

nix
# modules/audio.nix
nixos.modules.pc = { /* content */ };

The two examples look almost identical, and the difference is entirely in the key. In the first, the audio module stands alone under the name audio. In the second, the same content is filed under pc, and a second file that also sets nixos.modules.pc merges with it instead of replacing it.

That is the whole trick, and it is why deferredModule is listed as required reading. The option type is what tells the module system that the value is a module to be merged rather than a value to be overwritten, so the naming of the key becomes a grouping decision rather than a collision risk.

Three benefits: file type, automatic import, path independence

The first benefit is that the type of every file is known. The document puts it plainly: the common question of what is in that Nix file is made irrelevant, because non-entry point files contain a Nixpkgs module system module of the same class as the top-level configuration.

That is a real maintenance gain. In a tree where some files are modules, some are functions, some are values and some are imports, a reader has to open each file to know which. Here there is one answer, and it is checkable by a script or a reviewer in seconds.

The second benefit is automatic importing. Since all non-entry point files are top-level modules and their paths convey meaning only to the author, they can all be imported automatically using a trivial expression, or with a small library, and the document links to vic's import-tree for that purpose.

The third is file path independence, and it is the one with the widest consequences. In some patterns a path carries a specific meaning, such as the type of expression the file contains or which configuration it belongs to. In this pattern a path represents a feature, and the document is explicit that a file can be freely renamed and moved, and can be split when it grows too large or too complex.

Splitting is the part that matters in practice. A configuration that outgrows one file is normally a configuration you stop touching, because splitting it means changing the import structure. Here the split is a new file at a new path, and the import is automatic.

The anti-patterns section is the most actionable part

The document does not stop at the pattern, it also names what not to do, and the first anti-pattern is the sharpest: not declaring options.

The argument is that using only existing options, such as flake-parts' own flake.modules, for the storage of lower-level modules prevents the team from translating their mental model of the system into code. Declaring options for the storage of modules is easy:

nix
# modules/nixos/base.nix
{lib, ...}: {
  options.nixos.base = lib.mkOption {
    type = lib.types.deferredModule;
  };
}

And using them in another top-level module is equally easy:

nix
# modules/nixos/pc.nix
{config, lib, ...}: {
  options.nixos.pc = lib.mkOption {
    type = lib.types.deferredModule;
  };
  config.nixos.pc = config.nixos.base;
}

So the advice is to go ahead and model the infrastructure the way that serves you best. The option names are yours to choose, the type is deferredModule so that merging behaves, and the second file shows the reassignment pattern where one named module is pointed at another.

The second anti-pattern is a specialArgs pass-through, where in a non-dendritic pattern some Nix files are lower-level modules that have to be handed values through the specialArgs mechanism. The section is cut off in the documentation available here, so the details of the anti-pattern and its replacement are not visible, and the argument has to be read in the full README.

Adoptions, required skills and the state of the repository

The document lists one adoption it can vouch for, the author's own infrastructure repository with a link to the adoption commit. The rest are listed as examples the author cannot vouch for, including a vix pull request, a nixos-x260 pull request with a blog post about refactoring infrastructure as code configurations, a Horizon Haskell GitLab CI repository, and several personal configuration repositories from different authors.

That list is evidence of interest rather than of a maintained implementation, and it is worth reading that way. The pattern is applied by hand in each repository, which means each adopter has to make the same decisions about option names and file layout.

The required skills are stated as a precondition rather than a nicety: understanding the dendritic pattern strictly depends on fair comprehension of the Nix language, the Nixpkgs module system, and the deferredModule type. That third item is the one most likely to be unfamiliar, since it is an option type rather than a general concept, and the pattern leans on it for the merging behaviour.

The community is a GitHub Discussions area and a Matrix room, and the README collects testimonials from a few users, one of them noting the idea of every file being a top-level module and the intention to adopt it everywhere. The licence is MIT and the repository is not archived, with the last push on 2026-09-04 and no GitHub releases, which is the expected shape for a document that is versioned by its commit history rather than by tags.

Editorial conclusion

dendritic fits a Nix user who keeps more than one configuration, shares modules between them, and has re-architected the same tree more than once, because the pattern removes the question of what a given file is and lets paths carry feature names. It does not fit a single-machine configuration that fits in one file, and it is not a tool, so there is nothing to install and no upgrade path to think about. Before adopting it, read the anti-patterns section, particularly on declaring options rather than borrowing flake-parts' own, and be aware that understanding it properly requires the Nix language, the Nixpkgs module system and the deferredModule option type, which the document lists as required reading.

Frequently asked questions

What is the dendritic pattern in Nix?

It is a usage pattern for the Nixpkgs module system in which every Nix file except entry points such as default.nix and flake.nix is a module of a single top-level configuration, and each top-level module implements one feature across all configurations it applies to, at a path that names that feature.

What does deferredModule do in the dendritic pattern?

It provides value merging, so multiple lower-level module values can merge under one distinct name instead of overwriting each other. That is what lets a file set nixos.modules.pc and another file add to the same option.

Do I need flake-parts to use the dendritic pattern?

No. The document says the top-level configuration is commonly a flake-parts configuration but does not have to be, that alternatives to flake-parts may exist, and that the module system can be used directly through lib.evalModules.

What knowledge does the dendritic pattern require?

The document lists three prerequisites: the Nix language, the Nixpkgs module system, and the deferredModule type. It says understanding the pattern strictly depends on fair comprehension of all three.

Is dendritic a package I can install?

No. The repository holds a LICENSE, a README and a logo, and the project is described as a usage pattern rather than a library. The licence is MIT and the repository has no GitHub releases, with the last push on 2026-09-04.

Official sources

  1. Issues
  2. License: MIT
  3. mightyiam/dendritic on GitHub
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/mightyiam-dendritic.svg)](https://hysenlabs.com/projects/mightyiam-dendritic)

Was this useful?