/etc/nixos/roles/foo/default.nix has config for the 'foo' role (eg, I have a desktop role that enables all my GUI options)
configuration.nix and hardware-configuration.nix in /etc/nixos/ are symlinked to the actual files in /etc/nixos/hosts/<hostname>/
in the imports section of each machine's configuration.nix, I import /etc/nixos/roles/foo for each role the machine should use. for your graphics card example, I have 'nvidia' and 'nvidia470' roles that pull in their respective nvidia driver (due to an old gaming laptop that requires the legacy driver version)
I have a 'core' role that all machines import, with the global config I want on every host
this allows me to version-control my entire /etc/nixos directory (managed as a private git repo, replicated using syncthing rather than pushed to Github/Gitlab/etc). the symlinks in /etc/nixos are in .gitignore because they're machine-specific, and the actual per-host config files are able to be tracked in their own directories.
I also wipe my entire rootfs every boot with a zfs snapshot rollback[2] using the impermanence module[3] to keep specific stateful data one one of two datasets with regular snapshots: one is backed up with zfs send, the other is just for cache between reboots.
It took a little puzzling to get started, because I didn’t know about the impermanence module at first, so I built my own hacky solution. But I really love this setup. And the way I don’t have cruft to clean.
Also my backups are so much smaller now :’-)
Nix flakes lets you define as many configurations as you want, and (if you don't specify one) will select based on the hostname.