Workflows with flakes

Hello all,

I was wondering if anyone has found a good workflow for using flakes with multiple small packages. I have a few small programs, some of which are dependencies of one another, and I’m questioning how best to package them. The options seem to be:

  1. Give each its own github repo, no matter how tiny they are, and each with its own flake.nix at base. This works fine, but if you are using these packages as dependencies in another flake, your inputs section for that flake gets quite long and quite specific.
  2. Put everything in a single repo. This repo has sub-directories for each package, each sub-directory with its own flake.nix. A root-level flake.nix then has all these sub-packages’ flakes as an input, and has a packages output that contains all the sub-packages. This is neat for end-use as you can then get all your packages from this packages attribute of the root-level flake, like a channel. But it’s a little awkward for development, because even when working with a local copy of the repo, your sub-packages’ inputs are still of the form inputs = { packageA.url = github:<owner>/<repo> }, and so are still being obtained from github. It works if you swap all the inputs to eg packageA.url = path:./package-a-dir but then you have to change these back before pushing again.
  3. Mix the two approaches by using approach 1, but then creating an additional repo that holds a kind of master flake that pulls in all the other repos as inputs, and puts them in its package attribute.

If there’s a good or canonical solution to this I’d be glad to learn it. Approach 2 is most ergonomic in some ways, but having to change between local path and github for the root-level flake inputs between pushes is awkward. I was wondering if there was some way to tell nix to look at a local path if the root-level flake is being called locally, but a path within the repo if the root-level flake is being called from a remote location, but I can’t see anything in the documentation that seems to facilitate that.

Thanks for any help!

With experimentation, using eg inputs = { packageA.url = path:./package-a-dir } does actually work both locally and remotely. However it suffers badly from the problem described with sub-flakes here: Allow flakes to refer to other flakes by relative path · Issue #3978 · NixOS/nix · GitHub, to the extent that it’s not really practical.

1 Like

Have a look at nix registry – essentially symbolic links for flake repos. Although not a full solution to your workflow question, it may help a bit.

I started out with individual repos per package, but I grew tired of updating the inputs (namely nixpkgs) in so many repos. Nowadays I use a single repo containing most of my packages, but I only have one flake.nix You can see the repo here.

You can also invert what you described in #3; Have a single repo with all of your packages, and also have individual repos which pull in the monolithic repo but only expose a single package.

1 Like

I like approach 3 significantly better exactly for that reason, except instead of having sub-flakes just write the packages as normal code repos and use normal nix semantics for packaging them in the master repo.

It does depend a bit on the size and scope of your packages though.

Update hell bites you especially badly if your packages have inter-dependencies, because otherwise you quickly end up maintaining scripts just to make sure you can update your root packages, update the packages that depended on them, update their dependants, and so on.

Mimicking nixpkgs leaves you with a lot of tried ways of managing your code. If you write utility flakes (flake libraries, external nix modules, what have you), splitting them up makes more sense.

Thanks, yes, I’ve gone with approach 3 and it seems to be working out relatively smoothly so far. I still think that for these little packages, having all the flakes in the same repo, and then having them compose (eg approach 2) is conceptually better, hopefully the issue with lockfiles that’s blocking that gets ironed out at some point.

Thanks! Out of interest, why were you updating nixpkgs for all your repos? Just out of a general sense that you’d like to stay up-to-date? So far I think I’m happy with the idea of different packages being on different nixpkgs versions. The times I’ve tried to do full-blown system-wide updates in the past (eg nix-rebuild switch --update-all, or whatever the most aggressive option was in the days of channels) I usually came to regret it.

Yes, I like to stay up to date and save some space on my SSD.

1 Like