After nine moths of using flake-parts in several projects I’ve refactored my personal infrastructure repository to adhere to a pattern; every Nix file is a flake-parts module.
I have found this pattern liberating and therefore sharing. The readme has a few words on the matter.
How is that some modules are a function that return an attribute set, others are a function that return an attribute set whose main value is also a function and others are plain attribute sets?
Modules are of the structure x or moduleArgs: x, where x is some conformant attrset.
In flake-parts there are nested module system evaluations, so you could have fpModuleArgs: { perSystem = perSystemModuleArgs: perSystemAttrs; ... }, and so on. I guess that’s why some find f-p confusing to use.
I don’t find fp confusing at all. I’m more than used to high order functions (in either direction, taking or returning functions), recursion and all the usual jazz. But after reading the flakes on that repo, and reading probably 55% of flake-parts docs I was completely oblivious at what is making possible to return one or the other, and even worse, what to expect as input or what will be produced as output.
This black magic is probably very convenient, but it is very hard to understand for a newcomer
That looks like a file that is a NixOS module, isn’t it? In the pattern I’m describing each file is a flake-parts module. All files are flake-parts modules.
I guess I can see the advantages of importing all files instead of having to follow a predefined folder structure (like rails conventions). Reading your configs I can see the advantage of defining cross-cutting concerns independent of the file location.
I’ll be exploring your pattern on my own setup, and will use flake-parts a lot more on my published nix flakes :).
Now , -at the cost of being taken as a person who would publish two-lines isEven function as an npm package- I just published a flake inspired by yours here:
But that’s quite the opposite of what’s presented in the “every file as module” idea.
I have specially written a module loader based on haumea, whether it is every file as module or importNixOS modules as a tree or other hierarchical requirements, it depends on the direct functions of the loader and transformer.
Thanks for the inspiration, this makes everything cleaner!
I wish I could have used Haumea for loading the modules, but after hours of trying, I couldn’t get anywhere. I therefore used GitHub - vic/import-tree: Import all nix files in a directory tree. and in less than 5 minutes it was working. There’s a bit of frustration there, but I have something working and easy to reason about now.
This week I finally ported my osConfigurations.nix from numtide/blueprint to this pattern, all files being flake-parts modules.
One thing I loved (already noted by @mightyiam on their post) is that with this pattern you think more in term of “features” and not on how/where they are applied (other frameworks/patterns focus on imposing a directory structure).
For example, my rdesk.nix (remote-desktop feature) defines a homeManager (input-leap mouse multiplexer app) and a nixos module (nixos firewall rules) in the same file since both configs are part of the very same feature but one applies settings at the os-level and another at the home-level.
Same for my user.nix that exposes and re-uses my home config on my nixos, darwin hosts and standalone home-manager.
@drupol, @mightyiam, I’m thinking about creating a tiny github repo dedicated to this pattern (and have links to existing configurations using it - ours three as far as I know), perhaps a couple of nix templates and documentation on things we have found useful about this pattern. Perhaps, we even could provide “collections” of flake-parts modules that people could import on their flake and get started with fully functioning configs, something akin to configuration frameworks for neovim, spacemacs/doom-emacs layers.
@drupol@vic everyone, I love the idea of a dedicated home for this pattern because I think it’s useful enough to justify it. If we can build such a resource I think that that will contribute to more sharing, more interest and more usage. And I think that that would translate into value for flake users. One use case I think of is hordes of Linux PC users newly adopting NixOS. It’s happening:
And we can spare these new users months worth of learning. We can increase the rate of adoption by decreasing the rate of giving up because “there are too many ways to do things and where do I start?”.
So here is a stub repository in which I hope we will collaborate in creating a refined demonstration of how to use flake-parts and possibly even collaborate on some related utilities farther down the line.
I lieu of other naming suggestions I thought about it disproportionally and named it The Dendritic Pattern.
If anyone wants to collaborate synchronously on this, I’m open to that as well.
I just switched my config to a flake-parts module I made to simplify the pattern a bit for me. I mainly made it to have a nicer syntax for using nixos and home-manager modules in the same file, and for defining the hosts and their feature tags. Kinda hacky atm and I was rushing to switch to it so a lot of modules need to be split up, but it works.
For people following this thread, I’ve added an issue #1 at Dendritic repo (your input is welcome), about writing some example that shows how the Dendritic Pattern is not just about loading all files at once, it is more about defining cross-cutting concerns (or features) across different module classes, flake/nixos/darwin/homeManager/other-class levels, grouping same-purpose configurations together, but still giving you flexibility on where these concerns are defined and applied.
So its more about thinking in “features” than a fixed directory/osConfigurations definition structure.