I used to use Niv, but these days I find it more convenient to just call `builtins.fetchGit` where it's needed, rather than faffing with external files/tools (although https://hackage.haskell.org/package/update-nix-fetchgit can be useful). It's certainly much nicer than the "olden days" of `nixpkgs.fetchgit`, which required an "impure" copy of Nixpkgs (like <nixpkgs>) in order to fetch a pinned copy!
I tend to have a single git repo with my system config, which uses import-from-derivation to grab a bunch of other stuff; and defines a single "package" that's a big `buildEnv` of all the programs I want. That seems to work fine across NixOS (on an old i686 Thinkpad), an old Ubuntu desktop, macOS (a couple of work laptops; old one used nix-darwin, new one just uses nix-env), and I'm currently trying it on nixos-mobile (on my Pinephone).
I tend to have a single git repo with my system config, which uses import-from-derivation to grab a bunch of other stuff; and defines a single "package" that's a big `buildEnv` of all the programs I want. That seems to work fine across NixOS (on an old i686 Thinkpad), an old Ubuntu desktop, macOS (a couple of work laptops; old one used nix-darwin, new one just uses nix-env), and I'm currently trying it on nixos-mobile (on my Pinephone).