Moving from channels to flakes
I’ve been running my homelab on NixOS for a few months now. The migration from debian enables me to have a single configuration that involves only doing the following steps to replicate the single machine setup in a new environment
- Rotate the
sops-nixbacked secrets. - Setup
sshto the VPN provider, cloud backup provider. - Clone the backed-up data directory to local. I still use
resticfor backups. - Applying the single-machine configuration, I get an exact replica of the machine that I’m migrating from. (Nope!)
The default way Nix runs is through Channels. A NixOS system subscribes to a channel, for example a 25.05 release isn’t fixed. The security/minor version patches are continuously sent to this channel and the versions of dependencies of your environment are not exactly pinned. So when you move to a new system and try to replicate your deterministic environment, your backed-up data might not be compatible with the operating system you just installed.
Running these commands will catch your system up to the latest nixpkgs (the source of your dependency tree) in an existing system.
sudo nixos-rebuild switch --upgrade
Without doing this, if you migrate to a new system it automatically picks up the latest commit in 25.05 even though you might be in an older commit of this channel in your old environment, and thus the same Nix config produces different environments.
Flakes are experimental and as you already guessed, an alternative to the default way of writing Nix configuration (both for the NixOS, and “Nix” the build system).
But unlike channels, they lock the “nixpkgs” repository to a specific commit alongside the system configuration in your resulting system, and with it if you run the same NixOS configuration in a different machine, you will have a deterministic, and reproduced environment. Although, you must update the nixpkgs source in a timely manner, to receive security patches. But by using flakes, you own this responsibility instead of relying on NixOS Channels.
Practically you do the following steps
-
nixos-version --revisionprints the the running system’srevision. To keep the individual packages stable, the new flake based system MUST use this revision. -
The flake alongside your
configuration.nixlooks like this. It only acts as a tiny wrapper that propagatesnixpkgsbut it could look more complex eventually.{ description = "NixOS configuration (migrated from channels)"; inputs = { nixpkgs.url = "github:NixOS/nixpkgs/<REVISION>"; }; outputs = { self, nixpkgs, ... }: { nixosConfigurations.newmachina = nixpkgs.lib.nixosSystem { system = "x86_64-linux"; modules = [ ./configuration.nix ]; }; }; } -
nixos-rebuild build --flake .#newmachinaoutputs a./resultthat’s the closure of the new version of your machine. One can runnix store diff-closures /run/current-system ./resultto ensure that the new closure only has the following diffs. This guarantees that none of your working software would fail when yourebuild.- The updated version from your local channel-provided
nixpkgsto a pinnednixpkgs:<REVISION>. - The source code of the newly checked-in
nixpkgs:<REVISION>.
- The updated version from your local channel-provided
I would also recommend practicing this exercise in a “staging” system first before changing your actual homeserver. That’s it, do a sudo nixos-rebuild switch --flake .#newmachina and your flake-based NixOS is working independent of channels.
And, as a result if you apply this configuration as mentioned in Step 4 during the start of this document, you’ll have a bit for bit replica of your old system’s build.