Best practices: flakes for related projects

I’m part of an OSS organization (call it theproject) with a constellation of related repositories. Imagine the organization is theproject. Then there are GitHub repos:

  • theproject/service1
  • theproject/service2
  • theproject/cli
  • theproject/website

I’d like to Nix-ify these things, probably in the following order:

  1. the CLI, which should be sufficient for most end-users
  2. the services, which would be nice for development and there may be a few non-contributors running it
  3. the website, which would strictly benefit contributors

I’m not very familiar with flakes, but it seems like that’s the way things are moving. As of today, what are the best practices here? Ex.

  • should I just add these things to Nixpkgs directly?
  • should I flake-ify each repo individually?
  • should I flake-ify each repo individually, then have one shared theproject/flake repo that pulls them all in?
  • or should I keep all (most of) the Nix config in the theproject/flake repo?
  • both Nixpkgs and flakes? how do I keep them in sync?
  • something else I haven’t thought of

I’m looking to future-proof this (to the extent possible). Ideally at least the CLI would be accessible to users without flakes installed.

Any guidance would be appreciated! (And sorry if this is a dupe, I had a hard time figuring out what to search for.)

Each separate project should have its own flake.

2 Likes

You can also look at myme.no - NixOS: The Ultimate Dev Environment?

2 Likes

Thanks!

If I have flakes for each project, is it pretty easy to get those into Nixpkgs? Or will I essentially have to repackage each project?

Is this really agreed on? I’ve found that CI-based updates become cumbersome if the projects depend on each other. Not impossible, but if you want to update dependencies using nix flake update this means you need to sequence the updates correctly (because otherwise your pins become out of date and your test suite doesn’t test the actual latest state), which may or may not be possible without human intervention depending on your merge and branching policy.

And before anyone says just not to update your pins, that isn’t exactly reasonable if you’d like to stay on top of security updates, even if you can override pins downstream. That just means that you can’t guarantee the project can be built safely downstream.

You could use the flake registry, but that only works for things officially pinned in the flake repos, so it doesn’t really work if the projects depend on each other. If you can control the registries of all systems this will ever be built on, that’s maybe an option, which may be more feasible for an organization, but I don’t think that should be the state of the art.

A smart branching strategy with a dedicated stable branch, and CI to force reverse updates against the other repos can help, but I think in general in this kind of situation the API surfaces between the applications are usually not clear enough for that kind of setup.

Very fancy scripting that uses --override-inputs is maybe an option, but I find that most CI systems are too limited to allow multi-repo updates like that.

Personally, I think overall I’ve started to favor a monorepo approach for closely related projects, but that of course has its own downsides, and it is annoying for tool issues to be the reason behind project structure.

Either way, I don’t think it’s clear-cut enough to just state “obviously, multiple flakes”.