That's too much of a simplification. In NixOS you still have global configuration files, such as /etc/fstab. However, they are symlinks to Nix store paths that are associated with the current generation.
However, NixOS installations can also end up accumulating configuration and state files that stick around when they are not defined declaratively. E.g. if you enable ssh, host keys are generated in /etc/ssh. Even if you disable ssh, these files will stick around.
You can avoid such accidental state [1], since NixOS will happily boot from a filesystem with just /boot and /nix and reconstruct the rest upon system activation. But it is quite a bit of work, since you need to manually specify what state you want to preserve (e.g. SSH host key files). Also, it currently does not work nicely with some systemd units that barf out if you make /var/run entries symlinks.
I’m just getting started with Nix, with the explicit goal of making my entire system defined in a private , remote git repo. I want to be able to rapidly re-provision my entire user environment on a new machine, including applications, preferences, etc.
For the moment I’m doing this on MacOS with the nix package manager. I’ll eventually move to NixOS. I tried to run NixOS in VirtualBox, but couldn’t get screen resizing to work despite using the official ISO which is supposed to have the appropriate extensions installed.
My current hurdle is exactly the topic of this thread: non-binary configs. For example, what am I supposed to do with .zprofile? I think I’m supposed to write a custom Nix derivation for ZSH that includes any and all customizations. I’m concerned that might cause problems with MacOS system ZSH. I can probably fix that with a custom login shell?
Anyway it’s fun, but complicated and diversely documented. Gonna take a while to sort it all out.
My current hurdle is exactly the topic of this thread: non-binary configs. For example, what am I supposed to do with .zprofile? I think I’m supposed to write a custom Nix derivation for ZSH that includes any and all customizations. I’m concerned that might cause problems with MacOS system ZSH. I can probably fix that with a custom login shell?
I use both NixOS and macOS. You can take two routes: 1. you can continue using Apple's /bin/zsh and just use a .zprofile generated using Nix (e.g. home-manager). Generally, the differences between zsh versions are not that large and it just works. This is what I have been doing with my Mac. 2. You could change your shell, either system-wide, or just for Terminal.app to ~/.nix-profile/bin/zsh.
I’ll eventually move to NixOS. I tried to run NixOS in VirtualBox, but couldn’t get screen resizing to work despite using the official ISO which is supposed to have the appropriate extensions installed.
If you have some leftover hardware, try it! NixOS is a different experience altogether and cannot be paralleled by Nix on macOS or a Linux distribution. Being able to declaratively define your whole system is insanely cool and powerful. Fully reproducible machines. Also, you can try out stuff without any harm. Just switch back to the previous working generation (or try the configuration in a VM with nixos-rebuild build-vm) if you are not happy.
> I think I’m supposed to write a custom Nix derivation for ZSH that includes any and all customizations.
Nix supports lots of approaches, with a varying degree of "buy in". I wouldn't say you're "supposed" to do one thing or another, although some things would definitely be non-Pareto-optimal (i.e. you could achieve all the same benefits with fewer downsides).
In the case of .zprofile, I would consider any of the following to be reasonable:
- A normal config file sitting on your machine, edited as needed, not version controlled.
- A symlink to a git repo of configs/dotfiles (this is what I do)
- Directly version-controlling your home dir in some way
- Writing the config content as a string in a Nix file, and having Nix put it in place upon rebuild (I do this with files in /etc)
- Having a Nix 'activation script' which copies/symlinks config files into place (this is what I do, to automate symlinking things to my dotfiles repo)
- Wrapping/overriding the package such that it always loads the desired config (e.g. by replacing the binary with a wrapper which prepends a "use this config" flag).
--
The following has nothing to do with your question, but I felt like ranting about a tangentially-related topic; it's not directed at you ;)
I often see "extremism" when Nix is brought up; e.g. if someone wants help managing non-Python dependencies of their Python app, and someone recommends trying Nix, it's often dismissed along the lines of "I don't have time to throw away my whole setup and start over with the Nix way of doing things, even if were better". The thing is, using Nix can actually be as simple as:
(import <nixpkgs> {}).runCommand "my-app" {} ''
Put any arbitrary bash commands here
''
I often treat Nix like "Make, but with snapshots". Nix 2.0 turned on 'sandboxing' by default, but if you turn that off you can do what you like: add '/usr/bin' to the PATH, 'wget' some arbitrary binaries into '/var', etc. You won't get the benefits of deterministic builds, rollbacks, concurrent versions, etc. but those don't matter if the prior method didn't have them either. Projects like Nixpkgs, and the experimental things people write about on their blogs, aren't the only way to do things; you don't have to throw the baby out with the bathwater.