Ported my NixOS desktop to finix (finit instead of systemd) and back again — notes

https://preview.redd.it/l5ap5n9rd7jh1.png?width=1280&format=png&auto=webp&s=78dc5d150be3cf85b962d1266bd7a4909afbc44a

finix is a Nix distro built around finit as PID 1 instead of systemd. Flakes, modules, nixos-rebuild — all familiar. I put it on a second disk and tried to bring my actual desktop over: niri, nvidia, a Quickshell bar, stylix, home-manager. Here's what I hit, in case it saves someone the evening.

The option tree looks like NixOS but isn't

nixos-generate-config output doesn't drop in as-is. Missing or renamed: hardware.enableRedistributableFirmware, nixpkgs.hostPlatform, boot.blacklistedKernelModules, xdg.portal.extraPortals (it's portals), users.users.<name>.hashedPassword (it's password). Nothing hard, but you find them one failed eval at a time.

Seat manager has to match your device manager

udev pairs with elogind, mdevd pairs with seatd. I ran udev + seatd. Result: niri started, reported zero outputs while the kernel happily listed both connected monitors, and polkit crash-looped. No error says "these don't go together" — it's in the community-modules laptop profile, if you go looking for it.

polkit crash-loops out of the box with elogind

finix builds polkit with useSystemd = !elogind.enable, then still tells finit notify = "systemd". The binary can no longer send that notification, so finit waits forever and gives up after 10 restarts. lib.mkForce "none" fixes it. Looks like a straight upstream oversight.

No systemd user session — this is the actual cost

  • home-manager works, but user services don't. Anything that was a systemd.user.service becomes a niri spawn-at-startup.
  • pipewire and wireplumber ship as packages with /etc config and no service at all. Nothing starts them; there's no socket activation either. So there's no audio server running until your session starts one. It surfaced as bluetooth headphones pairing, showing "connected," then dropping instantly — bluez finds no A2DP endpoint because wireplumber isn't there to register one.
  • Session env vars are a trap. environment.variables only lands in /etc/profile.d, which a greetd→niri session never sources. Same for home-manager's home.sessionVariables — that's how I ended up with a Qt shell drawing every icon as the missing-image checkerboard, because QT_QPA_PLATFORMTHEME never reached it. security.pam.environment is the answer.

Two things that cost me the most time

New finit services need a full reboot — nixos-rebuild switch writes /etc/finit.d/ but a running finit won't pick up a brand-new stanza. And services need log = true or stdout goes nowhere; I had a service silently skipped every boot over a capital letter in a binary name, visible only in dmesg.

Verdict

On a desktop I genuinely could not tell the difference — which is exactly what you want from an init system. But that cuts both ways: what cost me three tries and 35 hours was hand-rebuilding things systemd's user session did for free. finit's appeal is a small, readable PID 1; that argument is much stronger on a server or embedded box than on a machine with nvidia, bluetooth audio, and a Qt shell.

The part doing the real work — flakes, declarative config, rollbacks — is Nix, and it's identical on both. Going back to NixOS, but I'm glad I looked.

Posted Aug 13, 2026, 8:36 PM UTC

311
Loading comments…