Nixos-rebuild that doesn't change anything


I’m restructuring my NixOS code and I want to make sure that I actually don’t change anything in the resulting configuration.

If I understand man page, when I run nixos-rebuild dry-build and get no /nix/store/xxx output, then the new code didn’t change the resulting configuration and If I actually apply the configuration via nixos-rebuild boot / nixos-rebuild switch then I won’t see a new symlink /nix/var/nix/profiles/system-#-link and therefore no new generation will be created.

Could you please correct me if I’m wrong?

1 Like

Not necessarily.

--dry-run will print these XY derivations will be built when the evaluation produces derivations whose build outputs are not available in the store. That can also happen when you change your configuration to one that matches any of the previously built ones.

It is also possible to use repo metadata or other “impurities” in the configuration (e.g. to record a Git commit id of the Flake revision the system was built from), in which case the dry-build would print there are changes, even though they are just trivial.

This does appear to be the case, I did not know that. But nixos-rebuild does not do anything special, just updating the profile with nix-env:

And I do not see it documented in nix-env --set manual page so I assume it is just some kind of optimization and would not rely on it.

I would recommend instantiating/building the system derivation explicitly before and after, and comparing the produced store paths (or using nix-diff):

1 Like

Thank you very much for the answer.

In other words if I previouly had NixOS configured with a random option config.a.b.c = false but my current state of NixOS is config.a.b.c = true then it is possible that I run nixos-rebuild dry-build and see no output even my current state differ from the new configuration since both config.a.b.c derivations exist in my store (the false derivation hasn’t been garbage collected).

Thank you.

I tested that and this is how it works.

When I make a change in the code but I’m sure that change won’t actually change anything in my NixOS, I can run nixos-rebuild boot once or multiple times and I don’t get a new /nix/var/nix/profiles/system-#-link

Could you please explain what commands to run to built it before and after? I’m assuming you’re suggesting to use some nix commands and not nixos-rebuild to do this.

I use flakes and I always try to use the new nix command instead of nix-* commands so if you could give me an example that is flake compatible…

Thank you so much.

1 Like

Note that Nix will produce a different derivation if any of its dependencies changes. That is also the case for the top-level NixOS system derivation. So you will still get the drv output for your system derivation unless it is the same as one of the previously built ones.

Yes, I meant the interpolated command that nixos-rebuild runs here:

For example, nix build

1 Like

That is possible, but the probability is low. That tells me that dry-build is good for a quick verification. Thank you.

That command helped a lot. This is my testing:

nix build ./my/
mv -i result result-a
vi ... # change = false;
nix build ./i/nixos/w/v/
mv -i result result-b
nix build ./i/nixos/w/v/
mv -i result result-c
ls -l result-* /nix/var/nix/profiles/system-28-link
  • added spaces:
lrwxrwxrwx 1 root root 82 Jul 19 09:05 /nix/var/nix/profiles/system-28-link -> /nix/store/zhy4vx875g2m3x72najj3jyn4zvxc87k-nixos-system-n0-23.05.20230717.53657af
lrwxrwxrwx 1 root root 82 Jul 21 13:52 result-a ->                             /nix/store/zhy4vx875g2m3x72najj3jyn4zvxc87k-nixos-system-n0-23.05.20230717.53657af
lrwxrwxrwx 1 root root 82 Jul 21 13:58 result-b ->                             /nix/store/9dgrkj2v517fggby0499bd1jcv19ig21-nixos-system-n0-23.05.20230717.53657af
lrwxrwxrwx 1 root root 82 Jul 21 14:02 result-c ->                             /nix/store/9dgrkj2v517fggby0499bd1jcv19ig21-nixos-system-n0-23.05.20230717.53657af

That tells me that the result-a is 100% same as my current generation. So this comparison is also quick like dry-build but dry-build is 99% safe for my use case. nix build ./my/ is 100% safe for my use case and therefore better.

And I didn’t know about nix-diff so I tried it out:

  • expecting no output:
nix run github:Gabriella439/nix-diff result-b result-c
- result-b:{out}
+ result-c:{out}
  • expecting some output:
nix run github:Gabriella439/nix-diff result-a result-b
- result-a:{out}
+ result-b:{out}
• The input derivation named `etc` differs
  - /nix/store/awp7j97nq63v58xld430gd1afv8xq4bv-etc.drv:{out}
  + /nix/store/vzayijf31m974i0b7d50i3hlppy7wfbz-etc.drv:{out}
  • The set of input derivation names do not match:
      - etc-man_db.conf
  • The input derivation named `dbus-1` differs
    - /nix/store/gf2dv03x7lskkxpd3d3zlqb2z8xzmjgx-dbus-1.drv:{out}
    + /nix/store/jmjmm340ib6vgl6ddddfqbniwgvlz1gs-dbus-1.drv:{out}
    • The input derivation named `system-path` differs
      - /nix/store/7bb9bhlr1p4kbyh1c5xv3z7yw4qm78a0-system-path.drv:{out}
      + /nix/store/vm23k3mjgi42dn851b4c6dqwm9fc71h5-system-path.drv:{out}
      • The set of input derivation names do not match:
          - man-db-2.11.2
          - nixos-manpages

Fantastic tool!

Thank you @jtojnar !

1 Like

Recently I had the similar need and I wrote very simple script:

current=$(readlink -f -- /nix/var/nix/profiles/system)
new=$(nix build --no-link --print-out-paths .#nixosConfigurations."${1:-first}"

[[ ${current} == "${new}" ]] \
    && echo same \
	|| echo DIFF

@lans Notice --no-link --print-out-paths so you can run it in your Git repo and you don’t need to unlink result after.