How to add templates to a flake that uses `flake-utils.lib.eachSystem`

There is an asymmetry between flake outputs which are system-dependent (such as devShell) and those that are not (such as templates)

devShell.<system-1> = ...;
devShell.<system-2> = ...;
template = ...;

flake-utils.lib.eachSystem turns something like this

some-flake-output = ...;

into something like this

some-flake-output.<system-1> = ...;
some-flake-output.<system-2> = ...;

I have a flake that uses flake-utils.lib.eachSystem, to which I want to add some templates.

How can I prevent flake-utils.lib.eachSystem from making the templates system-specific?

Merge the output of the function with a second attrset that contains your non-systemed outputs.

yes, this will look ugly. flake-utils also creates problems if specific architectures need different handling, you deal with that the same way. I prefer avoiding flake-utils-style eachSystem things wherever it doesn’t create too much boilerplate or there is no actual immediate need.

Alternatively, consider nosys, it’s much nicer if you really feel the need for an eachSystem.

How would one avoid repetition without such helpers, if multiple systems are needed?

Not; but I find that often tweaks for specific platforms are needed anyway, so the duplication is fairly limited. Depends on the project, of course, and I’m sure you do in fact have a use case - hence I recommend nosys - but I believe many flakes use flake-utils without an actual need for it.

I get the impression I’m missing something. The only example I can think of, of a flake not needing it (or something like it, or nosys) would be a flake that only ever needs to work on a single system. And I would imagine that those are a tiny minority.

nosys does look quite nice. Though my first attempt at using it works locally, but (maybe) on GHA.

I think a significant majority of all flakes using flake-utils.forEachSystem have never even been tested on anything but x86_64-linux systems (I suppose also aarch64-darwin here and there these days). Plenty of flakes mostly intended for system configuration add it for devShells.

My mindset is that, if someone needs to use it on a different system, the new system can be added at that time, and that event can then also be used to confirm that the flake actually works on the new system (because someone with the requisite hardware to confirm this showed up).

Otherwise you have a bunch of flakes that seem to work on a dozen different architectures, but when you actually try it most of them fail to work.

This might be different in a corporate setting where you actually know what systems your organization deploys, what must be supported, and where you have time and resources to invest in testing all of this. But at least for the more hobbyist parts of the community I find that flake-utils is often abused.