Files
Nomarchy/docs/MIGRATION.md
Bernardo Magri 61d9ee1577 docs(migration): clarify installer vs @home-snapshots layout (#64)
Installer: disko @snapshots → /.snapshots + first-boot nested
/home/.snapshots. Migration machines may use top-level
@home-snapshots (TuringMachine); either works for snapper.
2026-07-10 09:39:03 +01:00

12 KiB
Raw Blame History

Migrating an existing NixOS machine to Nomarchy (no reinstall)

If your machine already runs NixOS, you do not need the installer or a reformat to adopt Nomarchy. Nomarchy is a flake; "installing" it onto an existing NixOS box means pointing nixos-rebuild at a Nomarchybased flake that reuses your current hardware-configuration.nix. Nothing repartitions, and your /home is never written to by an activation.

This guide is written generically, with TuringMachine — a Lenovo AMD Ryzen 7840U / Radeon 780M laptop, LUKS + btrfs, systemdboot — as the concrete worked example. Substitute your own values where called out.

The promise: every step below is reversible. You keep three independent rollback nets (NixOS generations, a btrfs snapshot, and the fact that nixos-rebuild test never changes the boot default), and your files live on a separate subvolume that no config switch touches.


0. Is your machine a good candidate?

Migration is cleanest when your machine already matches Nomarchy's assumptions. Check each:

Nomarchy expects Check it If it differs
systemdboot bootctl status → "Product: systemdboot" GRUB works too; keep your loader config in system.nix
btrfs with @/@home subvolumes findmnt -t btrfs ext4/xfs boot fine — you just don't get snapshots
@snapshots + @home-snapshots subvols in findmnt output snapper features need them; create them or skip snapshots
LUKS (optional, themed prompt) lsblk -f shows crypto_LUKS none — LUKS is optional
Already a flake config test -f /etc/nixos/flake.nix fine either way; you'll write a fresh flake regardless

Installer vs migration snapshot layout. A fresh Nomarchy install (disko) creates a top-level @snapshots subvolume mounted at /.snapshots, then a first-boot oneshot makes a nested /home/.snapshots under @home for snapper's home timeline — it does not create a separate top-level @home-snapshots. Migration machines (e.g. TuringMachine) may already use top-level @snapshots and @home-snapshots; that is fine. Snapper only needs a .snapshots path under each tracked subvolume (/ and /home), so either layout works — reuse what you have, or create the missing pieces if you want snapper without reformatting.

TuringMachine matches all of these, including the @snapshots / @home-snapshots subvolumes — so snapper works with zero disk work.

Version note. Nomarchy pins nixos-26.05. If you're on an older release (TuringMachine is on 25.11), the migration folds a onerelease upgrade into the switch. That's normal and supported — read the NixOS 26.05 release notes for option/package renames, and lean on generations if something regresses.


1. The two rules that protect your data

  1. Never bump system.stateVersion. It is an ondisk/service compatibility marker tied to when the machine was first installed — not the nixpkgs version. Nomarchy's template ships 26.05; you must change it back to your machine's original value. Find yours:

    $ nixos-option system.stateVersion   # or: nix eval .#nixosConfigurations.<host>.config.system.stateVersion
    "24.11"
    

    (TuringMachine: 24.11.)

  2. /home is never touched by an activation. A nixos-rebuild switch swaps the system generation; your data subvolume is untouched. The Phase 0 snapshot is beltandsuspenders, not a necessity for file safety.


Phase 0 — Safety net (nothing changes yet)

# Read-only btrfs snapshots of root and home — instant rollback targets.
sudo btrfs subvolume snapshot -r /       /.snapshots/pre-nomarchy-root
sudo btrfs subvolume snapshot -r /home   /home/.snapshots/pre-nomarchy-home

# Freeze your current config as a clean git baseline.
cd /etc/nixos && git add -A && git commit -m "pre-nomarchy baseline" || true

You are currently booted in a knowngood generation; it remains in the systemdboot menu throughout. Worst case at any later step: reboot and pick it.


Phase 1 — Build the Nomarchy flake alongside (no switch)

Stand the new config up in a working directory and build it without activating. This is the real safety line: iterate here until it builds green before anything touches the running system.

git clone https://git.bemagri.xyz/bernardo/nomarchy.git ~/nomarchy-migrate
cd ~/nomarchy-migrate
# Or start from the downstream template:
#   nix flake init -t "git+https://git.bemagri.xyz/bernardo/nomarchy.git?ref=v1"
#   (produces flake.nix/system.nix/home.nix/…)

A Nomarchy downstream flake owns exactly five files. Assemble them:

hardware-configuration.nix — reuse yours unchanged

Copy your existing hardware config in verbatim. This is what preserves your disks, LUKS, btrfs subvolumes and swap — the reason no reinstall is needed.

cp /etc/nixos/hosts/TuringMachine/hardware-configuration.nix ./hardware-configuration.nix

flake.nix — one mkFlake call (from the template)

{
  description = "TuringMachine — Nomarchy";
  inputs.nomarchy.url = "git+https://git.bemagri.xyz/bernardo/nomarchy.git?ref=v1";

  outputs = { nomarchy, ... }:
    nomarchy.lib.mkFlake {
      src = ./.;
      username = "bernardo";                 # <- your login name
      # Optional nixos-hardware profile(s) for your model. For an AMD laptop:
      #   hardwareProfile = [ "common-cpu-amd-pstate" "common-gpu-amd" "common-pc-laptop-ssd" ];
      # Names: https://github.com/NixOS/nixos-hardware  (verify before use)
      # Full hardware story (firmware, fingerprint, unsupported machines):
      #   docs/HARDWARE.md in the Nomarchy repo
    };
}

system.nix — machine specifics + your decisions

This is where your three migration decisions land: PPD power (no ryzenadj), no Secure Boot, and the stateVersion override.

{ pkgs, username, ... }:

{
  # Plain systemd-boot — no lanzaboote / Secure Boot.
  boot.loader.systemd-boot.enable = true;
  boot.loader.efi.canTouchEfiVariables = true;

  networking.hostName = "TuringMachine";
  time.timeZone = "Europe/London";           # your zone
  i18n.defaultLocale = "en_US.UTF-8";

  users.users.${username} = {
    isNormalUser = true;
    extraGroups = [ "wheel" "networkmanager" "video" "input" ];
  };

  # ── Power: Nomarchy's PPD (drops all custom ryzenadj/TLP tuning) ──────
  nomarchy.system.power = {
    enable = true;
    backend = "ppd";                         # power-profiles-daemon
    laptop = true;
    batteryChargeLimit = 80;                 # optional longevity cap
  };

  # ── AMD 7840U / Radeon 780M ──────────────────────────────────────────
  nomarchy.hardware.amd.enable = true;       # amd-pstate + radeonsi VA-API
  # nomarchy.hardware.amd.rocm.enable = true; # opt-in GPU compute (multi-GB)

  # CRITICAL: keep your ORIGINAL install's value — never Nomarchy's 26.05.
  system.stateVersion = "24.11";
}

Dropped on purpose (decisions 1 & 2): your old modules/services/power-management.nix ryzenadj stack, the lanzaboote input, and the power-max/power-stealth scripts. PPD's performance/balanced/powersaver profiles (switchable from the Waybar battery/profile icons and nomarchy-menu) replace them.

home.nix — your apps on top of Nomarchy's desktop

Start from the template's home.nix (it ships the default app set) and add your personal packages/config. Carry over anything you still want (e.g. your emacs setup).

{ pkgs, lib, ... }:

{
  # Nomarchy hardcodes home.stateVersion = "26.05". Moving home-manager's
  # stateVersion is low-risk, but if you want to pin your original:
  home.stateVersion = lib.mkForce "24.11";

  home.packages = with pkgs; [
    # your extras — e.g. emacs, language toolchains, …
  ];
}

theme-state.json

Copy the template's theme-state.json (or let nomarchy-menu theme write it after the switch). Your old nomarchy-state.nix prototype (schema nomarchy.theme = "nord" …) is retired — the current distro uses this JSON. nord is a shipped Nomarchy theme, so you lose nothing.

The build gate

nixos-rebuild build --flake ~/nomarchy-migrate#default

Zero activation — this only evaluates and builds the system closure. Fix any eval/build error here, in isolation, before touching the running machine. Expect to resolve a few 25.11→26.05 option renames.


Phase 2 — Reversible activation

# Activates now, but does NOT become the boot default. If the session
# breaks, REBOOT and you are back in your old generation, untouched.
sudo nixos-rebuild test --flake ~/nomarchy-migrate#default

# Bring the desktop (home-manager) up:
home-manager switch --flake ~/nomarchy-migrate#bernardo

Log into Hyprland and sanitycheck: Waybar renders, SUPER+M opens the menu, theming is coherent, SUPER+? shows the cheatsheet. Confirm the machinespecific things you care about still work — suspend/hibernate, the AMD GPU (vainfo → radeonsi), display brightness.

If anything is wrong: reboot → old generation. Nothing is committed as default yet.


Phase 3 — Reconcile

  • Power: verify powerprofilesctl get works and the Waybar battery / powerprofile icons open the power menu. Your ryzenadj scripts are gone; if you miss a specific TDP behaviour, that's a followup, not a blocker.
  • Theme: nomarchy-menu theme → pick nord (writes theme-state.json).
  • Snapshots: nomarchy-menu → System → Snapshots should see your existing @snapshots subvolume.
  • Secrets/services: if you relied on agenixmanaged secrets for a service, layer agenix back into system.nix as a machinespecific import (Nomarchy doesn't manage secrets). If you don't need them, leave them out — this is a full cutover.

Phase 4 — Cutover

Once a test boot is solid:

# Move the flake to its canonical home and make it the boot default.
mv ~/nomarchy-migrate ~/.nomarchy
sudo nixos-rebuild switch --flake ~/.nomarchy#default
home-manager switch --flake ~/.nomarchy#bernardo

# Point /etc/nixos at the flake (optional but conventional).
sudo mv /etc/nixos /etc/nixos.pre-nomarchy
sudo ln -s ~/.nomarchy /etc/nixos

From here you're on the standard Nomarchy update flow: sys-update (lock + system) then home-update (desktop) — always in that order (a lock bump before the home switch, or desktop changes are skipped against the old lock).


Rollback, at any point

Net How
NixOS generation Reboot → pick the previous entry in the systemdboot menu.
nixos-rebuild test Never sets the boot default; a reboot reverts it.
btrfs snapshot Restore /.snapshots/pre-nomarchy-root (see docs/RECOVERY.md).
git baseline /etc/nixos.pre-nomarchy (and the prenomarchy commit) is your old config verbatim.

/home is untouched by all of the above.


Postmigration cleanup (once you're confident)

  • Delete the safety snapshots: sudo btrfs subvolume delete /.snapshots/pre-nomarchy-root (and the home one).
  • Remove /etc/nixos.pre-nomarchy and the old perhost modules you cut (ryzenadj powermanagement, lanzaboote, the nomarchy-state.nix prototype).
  • Prune old generations: sudo nix-collect-garbage -d.

TuringMachine — the decisions, at a glance

Item Choice
Power Nomarchy PPD (backend = "ppd"); all ryzenadj/TLP tuning dropped
Secure Boot Off — plain systemdboot, lanzaboote dropped
Scope Full cutover to Nomarchy's structure
system.stateVersion 24.11 (preserved from original install)
Hardware nomarchy.hardware.amd.enable = true (7840U / Radeon 780M)
Bootloader systemdboot (unchanged — already matched)
Filesystem LUKS + btrfs, existing subvolumes reused (incl. snapshot subvols)