Getting the new build-image functionality working as a simple example

I’m trying to try out the new native nix build image functionality.

I am trying to get the following helloworld-ish example building so that I can go from there:

{
  description = "NixOS raw image buildable from macOS";

  inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11";

  outputs = { self, nixpkgs }: {
    nixosConfigurations.vm = nixpkgs.lib.nixosSystem {
      system = "aarch64-linux";
      modules = [
        ({ ... }: {
          boot.loader.systemd-boot.enable = true;
          boot.loader.efi.canTouchEfiVariables = true;
    	})
      ];
    };
  };
}

and build with nix build --system aarch64-linux .#nixosConfigurations.vm.config.system.build.images.raw

and throws the following error

Setting maximal mount count to -1
Setting interval between checks to 0 seconds
Setting time filesystem last checked to Wed Dec 31 00:11:41 2025

setting up /etc...
efiSysMountPoint = '/boot' is not a mounted partition. Is the path configured correctly?
Traceback (most recent call last):
  File "/nix/store/6lwgi1hm78yzv847ls4jp7cm940falyz-systemd-boot/bin/systemd-boot", line 452, in <module>
    main()
    ~~~~^^
  File "/nix/store/6lwgi1hm78yzv847ls4jp7cm940falyz-systemd-boot/bin/systemd-boot", line 432, in main
    run([CHECK_MOUNTPOINTS])
    ~~~^^^^^^^^^^^^^^^^^^^^^
  File "/nix/store/6lwgi1hm78yzv847ls4jp7cm940falyz-systemd-boot/bin/systemd-boot", line 58, in run
    return subprocess.run(cmd, check=True, text=True, stdout=stdout)
           ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/nix/store/lp1pfxqrslwn57x9n4lfvwfsmqdkvwhj-python3-3.13.9/lib/python3.13/subprocess.py", line 577, in run
    raise CalledProcessError(retcode, process.args,
                             output=stdout, stderr=stderr)
subprocess.CalledProcessError: Command '['/nix/store/5vrb7xsphy3czhih3yvw4ps6i5ikhpwi-check-mountpoints']' returned non-zero exit status 1.
Failed to install bootloader
[    7.860408] Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000100
[    7.861293] CPU: 0 UID: 0 PID: 1 Comm: cjvkhyqnqnmc997 Not tainted 6.12.63 #1-NixOS
[    7.861662] Hardware name: linux,dummy-virt (DT)
[    7.861954] Call trace:
[    7.862088]  dump_backtrace+0xd8/0x130
[    7.862365]  show_stack+0x20/0x38
[    7.862514]  dump_stack_lvl+0x60/0x80
[    7.862678]  dump_stack+0x18/0x28
[    7.862826]  panic+0x164/0x378
[    7.862966]  do_exit+0x9ec/0x9f8
[    7.863111]  do_group_exit+0x3c/0xa0
[    7.863268]  __arm64_sys_exit_group+0x20/0x28
[    7.863452]  invoke_syscall+0x50/0x120
[    7.863615]  el0_svc_common.constprop.0+0x48/0xf0
[    7.863821]  do_el0_svc+0x24/0x38
[    7.863968]  el0_svc+0xe8/0x148
[    7.864110]  el0t_64_sync_handler+0x120/0x130
[    7.864289]  el0t_64_sync+0x190/0x198
[    7.864553] Kernel Offset: 0x1240b3200000 from 0xffff800080000000
[    7.864618] PHYS_OFFSET: 0x40000000
[    7.864665] CPU features: 0x00,0000000d,0037797c,677e7f3f
[    7.864734] Memory Limit: none
[    7.864899] Rebooting in 1 seconds..

It builds ok without EFI being enabled - however I need EFI as I use apple hypervisor which does not support MBR.

How can I make this simple example work?

@phaer

1 Like

I would expect a minimal hello world to still need to declare fileSystems, including probably a /boot and / at bare minimum. Which aligns with the error you’re seeing. The bootloader install script checks that /boot is a mountpoint, as a safety, and is probably correctly warning you about a misconfiguration.

I actually tried this first (although guessing at what build-image labels the partitions)

and get the same error:

{
  description = "NixOS raw image buildable from macOS";

  inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11";

  outputs = { self, nixpkgs }: {
    nixosConfigurations.vm = nixpkgs.lib.nixosSystem {
      system = "aarch64-linux";
      modules = [
        ({ ... }: {
          boot.loader.systemd-boot.enable = true;
          boot.loader.efi.canTouchEfiVariables = true;
          boot.loader.efi.efiSysMountPoint = "/boot";
	      fileSystems."/" = {
            device = "/dev/disk/by-label/nixos";
            fsType = "ext4";
          };
          fileSystems."/boot" = {
            device = "/dev/disk/by-label/boot";
            fsType = "vfat";
          };
	    })
      ];
    };
  };
}

nixos-generators label the boot partition ESP (rather than boot) and I’ve tried that also to the same effect.

Ok I figured it out there is a raw builder and a raw-efi builder I was using raw.

This now works:

{
  description = "NixOS raw image buildable from macOS";

  inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11";

  outputs = { self, nixpkgs }: {
    nixosConfigurations.vm = nixpkgs.lib.nixosSystem {
      system = "aarch64-linux";
      modules = [];
    };
  };
}

trick was to build it like this and build with nix build --system aarch64-linux .#nixosConfigurations.vm.config.system.build.images.raw-efi

1 Like

Hello! You have already figured this out before I had seen the ping. The split between raw and raw-efi should be exactly the same as in nixos-generators as it’s upstreamed from there. Both just don’t create an ESP partition for non-EFI images. It’s defined in nixpkgs/nixos/modules/virtualisation/disk-image.nix at 4ffad61f23a8e1563f97ab2cef3ff5fce5de29f7 · NixOS/nixpkgs · GitHub.

(nixos-rebuild build-image --flake .#vm --image-variant raw-efi should build work the same; even on darwin, once nixos-rebuild is in your $PATH)

Thank you for your work on this, the work you have done is much more stable than the nixos-generators with large closures. Great job!

1 Like