- Authors
- Published on
How to Dual Boot NixOS and Windows
This post is part of a series about NixOS. The series is done in support of my upcoming Opus Magnum, "Practical NixOS: the Book", and you can read the detailed post here.
Should you find this article lacking some information, be sure to tell me in the comments or elsewhere, since it is a living document and I am very keen on expanding it.
Table of Contents (Click to Hide/Show)
- Bottom Line Up
- Resizing Windows Parition to Fit NixOS
- Flashing NixOS Image to USB Drive
- Installing NixOS with Graphical Installer
- Increasing Boot Partition Size
- Setting Up the Partition Layout
- Back-up Files from Boot Partition
- Recreate the Boot Partition
- Copy Files Back to Boot and Update NixOS Configuration
- Finale
Bottom Line Up
This article is applicable for any version of Windows, incl. Windows 10 and Windows 11.
Dualbooting NixOS and Windows is not a complex task. First, you'll use Windows to shrink its partition and make space for NixOS, and to flash a NixOS image to a USB drive. You would then install NixOS, and use GParted on NixOS to increase the Boot partition size.
You'll (obviously) need a PC that comes with Windows already, and a flash USB drive - and don't worry if it's already used for data storage.
It's easier to install NixOS after Windows (and in general, it's easier to install Linux after Windows). If you hadn't installed either of systems yet - install Windows first, and consider making Windows' Boot partition larger - 4 GiB, and not 100 MiB that comes from the default partitioning schema, otherwise you'll have to do some manual adjustments after.
A thing that drastically improves the NixOS installation experience is the GUI installer called Calamares, which was introduced in 2022. It simplifies initial configuration, and more importantly, unlike the pure terminal experience - it gives the confidence in the success of the installation process. I personally would still prefer CLI to a GUI though.
As I've mentioned - the only caveat to be aware of is the default 100 MiB Windows Boot partition. Due to the way the NixOS' bootloader - Systemd Boot - shares the same Boot partition and utilizes it to store Linux kernels, its size is insufficient, so you'll have to copy its contents, resize it, and then manually re-create it. It will require some usage of terminal interface, but is also rather straight-forward.
This article not only explains the sequence of steps to be performed, but also touches on the Why's of the things being they are, dives deeper to explain each step in thorough detail, and supplies enough context - regarding the ecosystem, historical, etc.
In the end, you will get a full solution, and not something you would have to tweak afterwards.
Resizing Windows Parition to Fit NixOS
Assuming you already have Windows 11 installed, our first step would be to shrink the Windows partition to make some space for NixOS.
In my initial layout, the laptop has a single 1 TB SSD fully occupied by Windows 11.
Go to the start menu, search for "disk management", or just open up a PowerShell and type in diskmgmt.msc
, then hit Enter
.
You should see Disk 0
with 3 paritions:
- EFI boot partition
- Primary NTFS partition containing Windows. The letter may be different for you, but most likely it would be "Disk C:".
- Recovery partition
Right-click the "Disk C:" partition, and choose "Shrink Volume...". We're going to give NixOS 400000 MBs (400 GBs), so slightly less than a half of the Drive's total size. Click "Shrink":
This will create unallocated free space:
In the end, we got 390.63 GB of free space instead of 400, because Windows cannot properly distinguish GBs from GiBs, where Gigabyte
is a marketing slang to sell you less storage for more money, while Gibibyte
is a proper unit of measurement. Whatever.
One out of two steps within Windows is complete! Up to the next.
Flashing NixOS Image to USB Drive
We're going to use an application called Ventoy to "burn" the NixOS Image to the USB drive.
Ventoy is a marvel of FOSS software engineering, no more, no less. It allows you to load an image onto a USB Drive in a unique way. Unlike traditional methods, it allows the USB Drive to remain usable as a general writeable storage, without turning it into a read-only device. Your cat pics and family photos can resize alongside NixOS bootable image. Not only that - with Ventoy, you can easily add multiple ISO images to the drive by simply copying them, not burning. This functionality lets you boot these images directly when starting your computer. According to the Ventoy website, they have successfully tested this feature with over 1100 different operating systems and utility images.
Go to Ventoy and grab a zip-file called ventoy-X.X.XXX-windows.zip
at the Downloads Page.
Right-click the downloaded ventoy-X.X.XXX-windows.zip
and unpack it. Run Ventoy2Disk.exe
, select the device and press the "Install" button.
The process is straight-forward, so after the USB flashing is done, your drive should be called "Ventoy", and feature the ventoy firmware.
Now, let's grab the latest NixOS stable image (24.05
at the time of writing) with Calamares GUI Installer featuring Gnome Desktop Environment. Go to the Downloads Page and you'll find it there, or use a direct link (x86_64). At the Downloads Page, you are also given a choice to download the installer with KDE Plasma Desktop Environment. It doesn't matter much which you choose, since this Desktop Environment is used just to enable the graphics of the NixOS Live USB system with Calamares Installer, while the Installer itself gives you flexibility to select almost any DE of your liking. Currently, GNOME
, KDE Plasma
, Xfce
, Pantheon
, Cinnamon
, MATE
, Enlightenment
, LXQt
, Budgie
, and no-desktop pure terminal could be chosen from the installer menu, and many-many more are available via NixOS options and from nixpkgs
after you've completed the installation.
After the download is finished, just copy the ISO image to the Ventoy drive and reboot the PC.
Installing NixOS with Graphical Installer
Immediately after restarting the PC you should enter the boot menu. Look up on google, how to do so. Most likely you should press or hold some F-key
or Delete
. If you see Windows login prompt instead of boot menu, restart your PC once again.
In the boot menu, use arrows to select the USB Drive and press Enter
. If the flash drive contains multiple bootable ISO images, all of these would be listed in the Ventoy menu. Select nixos-gnome-24.05-XXX-x86_64-linux.iso
, then press Boot in normal mod
, and finally press NixOS 24.05.XXX Installer
to boot into NixOS Live USB.
The installer greets you:
Use wired connection or WiFi to connect to the internet. WiFi drivers should already be available on the Live USB system, so to connect to the WiFi, click the battery and sound icons in top-right corner, then select your network SSID (name) and enter the password.
You may not proceed with the installation unless you make that "Network not available" message go away. After establishing the connection, press "Cancel" in the installer window and confirm your choice. Then click the pill and three dots menu in the top-left corner, look the to the bottom, and click the Orange Square to open up the Installer again.
The Calamares Installer's prompt will walk you through the selections of locales, keyboards, users settings, and desktop environment.
At the "Unfree Software" tab, enable the "Allow unfree software", because you would most likely want to install some, e.g. the VSCode editor.
At the "Partitions" tab, you may select the "Replace a partition" radio button, and then click on the grey bar representing free space. That would create one primary partition, and one Boot partition. Instead of selecting "Replace a partition" I suggest you to go with the "Manual partitioning" option to also create a swap partition.
At the "Partitions" tab, select the "Replace a partition" radio button, and then click on the grey bar representing the unallocated space we got from shrinking the Windows partition. That would create one primary partition, and one Boot partition.
You may also go with "Manual partitioning" for a more sophisticated setup - for exaple, you may also want to have a swap partition, even though such a partition is of little use on modern systems with sufficient RAM.
Click next to go to the "Summary", ensure that you're satisfied with the chosed settings, and the proceed to finalize the installation process to persist NixOS with the initial configuration.
You now have a working NixOS system which you may use, however it may prove troublesome very soon, unless you increase the Boot partition size.
Increasing Boot Partition Size
Now, we are ought to increase the Boot partition size. Unfortunately, GParted does not support resizing FAT32 partitions, thus we would have to copy its contents, delete it, then recreate with bigger size, and finally copy the contents back (after all, the contents are just files.)
Expect a lot of screenshots below, as I wanted to capture every step in full detail.
Setting Up the Partition Layout
Here's the initial alignment when you open GParted:
First, we would have to shrink the Windows 11 partition. Shrinking it from beginning (creating leading unallocated space) is exactly the same procedure as shrinking it from the end, but may take slightly more time, since files that may already occupy starting space would have to be moved (copied) "further" up the disk.
Right-click the Windows 11 partion (/dev/nvme0n1p3
with ntfs
file system) and select "Resize". The following prompt will pop up:
Be not afraid of the jumpscare warning below. Moving (resizing a partition from the beginning) is a safe operation. Be sure that your laptop is plugged into power, you probably don't want it to shutdown mid-process. Having backups in advance also helps, but, to be honest - you don't have to worry about it. I've done this multiple times without a backup (shame on me), and all such operations were successful and without any issues.
GParted interface is smart enough to figure out that if you increase the preceeding space, some other space has to be shrinked. You won't have to reach for a calculator to calculate all the values manually. Just enter the size of the space you want to de-allocate - in our case, the Boot partition is 100 MiB, and we want it to be 4 GiB = 4096 MiB, thus we need to add extra 4096-100 = 3996 MiB. Type in 3996
and press enter - GParted will then deduct the same amount from the size of partition ("New size"):
Ensure that the partiton is indeed of the desired size and has proper offset, and press enter.
Since there's one more partition sitting in-between Boot and Windows' main partition, we would have to offset it (not resize) by the same amount of 3996 MiB. This 16 MiB "Microsoft reserved partition" is the Recovery partition (briefly mentioned above), it's a legacy Windows thing, so do think about it too much. Right-click the partition (/dev/nvme0n1p2
with unknown
file system) and select resize. You'll see that it has 0 MiB of "Free space preceeding" and 3996 of "Free space following", let's swap these.
Type 3966
in place of zero, press enter. Again, GParted would be smart enough to shrink unallocated following free space to zero.
Finally, let's make Boot partition (EFI system partition /dev/nvme0n1p1
with fat32
) 4 GiB (4096 MiB) big:
Type 0
in place of 3996
, press enter - "New size" automatically becomes 4096, just as planned!
The layout before applying the operation then would look like this:
Press the green check mark to proceed with the operation. Applying new schema would take slightly longer than creating partitions from scratch or shrinking partitons from their end - GParted has to move the whole Windows - not the smallest of them! - "further" up the disk. The suggested estimate (10 minutes here) was close to the actual timing, and you should also expect some sensible number (10 to 30 minutes), depending on your disk's speed.
Oh no! It has completed 2 out of 3 operations and failed to grow FAT32! Well, that was totally expected - FAT32 is tons of legacy code, and noone in their right mind would want to jump into it to add suport for resizing FAT32 for non-windows tools. As you see, "GNU Parted cannot resize this partition to this size. We're working on it!".
2 other operations (shrinking Windows partition and moving the Windows recovery one) were actually successful, so let's delete and recreate the Boot.
You may also double-click the Boot partition, which now sports a warning triangle - the popup will tell you that most of the space on that partition is unallocated and you may fix it by using "Partition --> Check". This is also a lie.
Back-up Files from Boot Partition
Let's start backing-up the files from the Boot partition. You can use a temporary folder on the system. Or you may already have a backup in place, if you're that kind of person.
Since we're using a LiveUSB Installer Image, your active system currently has no access to the file system of the Boot partition - the Boot partition is not "mounted". To access the files, we have to "mount" the partition - create a folder on current system (the folder is not going to be persisted after reboot), and then instruct the Operating System to show files from the Boot partition as if they have belonged inside this folder.
To create a temporary folder, open up the terminal and run the following:
[root@nixos:/home/nixos]# mkdir /tmp/backed-up-boot
[root@nixos:/home/nixos]# mkdir /mnt/actual-boot
[root@nixos:/home/nixos]# mount /dev/nvme0n1p1 /mnt/actual-boot
The first and second commands will create backed-up-boot
directory under /tmp
directory, and actual-boot
directory under /mnt
directory. Both /tmp
and /mnt
directories, standing for "temporary" and "mount" respectively, are already present on virtually every Linux system, incl. NixOS. This choice of parent folders is somewhat arbitrary, as we could have created our directories under any other. But for the purposes of following the convention, the to be mounted Boot partition is going to reside under /mnt
, while its contents are going to be backed-up to a directory under /tmp
.
The third command instructs the system to list all the files on the Boot partition inside the newly-created actual-boot
directory, and make them available for read-write operations.
/dev
here stands for "device" - and it lists all the devices of this computer. Since Linux, being a derivative of Unix, conisders every thing in existence a file (a stream of bytes to be precise), disks, as well as partitions are listed under this directory, and exposed for different manipulations as files.
For illustrative purposes, let us now list the files on the Boot partition. For that, we'll use the tree
command. tree
is not available on the Installer Image, so we have to install it first:
[root@nixos:/home/nixos]# nix-shell -p tree
After installation, running tree /mnt/actual-boot
will produce roughly the following structure (some files like additional translations and fonts are omitted):
[nix-shell:/home/nixos]# tree /mnt/boot-to-copy/
/mnt/boot-to-copy/
├── EFI
│ ├── Boot
│ │ └── bootx64.efi
│ ├── Lenovo
│ │ └── BIOS
│ │ └── SelfHealing.fd
│ ├── Linux
│ ├── Microsoft
│ │ ├── Boot
│ │ │ ├── BCD
│ │ │ ├── BCD.LOG
│ │ │ ├── BCD.LOG1
│ │ │ ├── BCD.LOG2
│ │ │ ├── bg-BG
│ │ │ │ ├── bootmgfw.efi.mui
│ │ │ │ └── bootmgr.efi.mui
│ │ │ ├── bootmgfw.efi
│ │ │ ├── bootmgr.efi
│ │ │ ├── BOOTSTAT.DAT
│ │ │ ├── boot.stl
│ │ │ ├── CIPolicies
│ │ │ │ └── Active
│ │ │ │ ├── {5DAC656C-21AD-4A02-AB49-649917162E70}.cip
│ │ │ │ ├── {82443e1e-8a39-4b4a-96a8-f40ddc00b9f3}.cip
│ │ │ │ └── {CDD5CB55-DB68-4D71-AA38-3DF2B6473A52}.cip
│ │ │ ├── cs-CZ
│ │ │ │ ├── bootmgfw.efi.mui
│ │ │ │ ├── bootmgr.efi.mui
│ │ │ │ └── memtest.efi.mui
│ │ │ ├── fi-FI
│ │ │ │ ├── bootmgfw.efi.mui
│ │ │ │ ├── bootmgr.efi.mui
│ │ │ │ └── memtest.efi.mui
│ │ │ ├── Fonts
│ │ │ │ ├── chs_boot.ttf
│ │ │ │ └── wgl4_boot.ttf
│ │ │ ├── kd_02_10df.dll
│ │ │ ├── kd_0C_8086.dll
│ │ │ ├── kdnet_uart16550.dll
│ │ │ ├── kdstub.dll
│ │ │ ├── memtest.efi
│ │ │ ├── qps-ploc
│ │ │ │ └── memtest.efi.mui
│ │ │ ├── Resources
│ │ │ │ ├── bootres.dll
│ │ │ │ └── en-US
│ │ │ │ └── bootres.dll.mui
│ │ │ └── winsipolicy.p7b
│ │ └── Recovery
│ │ ├── BCD
│ │ ├── BCD.LOG
│ │ ├── BCD.LOG1
│ │ └── BCD.LOG2
│ ├── nixos
│ │ ├── icjw0k1sqbikanjm4hl1chp9cpzdn4sv-linux-6.8.2-bzImage.efi
│ │ └── mq9bchqh2czf9dxgfawiy4ag2d75qp7x-initrd-linux-6.8.2-initrd.efi
│ └── systemd
│ └── systemd-bootx64.efi
├── loader
│ ├── entries
│ │ ├── nixos-generation-1.conf
│ ├── entries.srel
│ ├── loader.conf
│ └── random-seed
└── System Volume Information
55 directories, 149 files
To copy the files, run the following:
[nix-shell:/home/nixos]# rsync -ah --progress /mnt/actual-boot /tmp/backed-up-boot
I use rsync -ah --progress
command instead of cp
, because it can show the operation's progress.
Finally, unmount the Boot partition to "disassociate" it from the running system and enable for partition-related operations with GParted (mind the spelling of umount
without n
):
[nix-shell:/home/nixos]# umount /tmp/actual-boot
Now, we're ready to recrate the Boot partion.
Recreate the Boot Partition
Right-click the Boot partition and mark it for deletion (it won't delete it yet). Unallocated space will appear in its place:
Double click the unallocated space to create the new partition. Allocate the entire space of 4096 MiB. You may end up with occasional 1 or 2 MiBs of unallocated space in-between some partitions due to how the data is physically aligned on the disk, but don't worry about it. Ensure, that you have created the partition as Primary Partiton
, fat32
file system, and named it EFI System Partition
:
The layout to be applied with new partition will then look like this:
Click the green check mark to start the creation of new partition.
Voila! Schema is applied, and the green check mark is greyed-out, since no more operations are pending:
An important step after applying the schema - since Boot is a special purpose partition, we have to mark it accordingly with proper partition flags. Right-click the Boot partition, select "Flags", and ensure that you have enabled 3 flags - boot
, esp
, and no_automount
. This operation does not require to be applied, so flags persist once you click "Close":
Copy Files Back to Boot and Update NixOS Configuration
The only thing remaining is to restore the files and to instruct NixOS to consider the newly-created partition as part of its configuration.
Remount the Boot partition and copy files back to it:
[root@nixos:/home/nixos]# mount /dev/nvme0n1p1 /mnt/actual-boot
[root@nixos:/home/nixos]# rsync -ah --progress /tmp/backed-up-boot /mnt/actual-boot
You can once again verify the contents of actual Boot with tree /mnt/actual-boot
- compare the number of files as shown in the last line of the output.
Unomunt Boot partition with umount /mnt/actual-boot
.
Now, you'll have to mount NixOS partition to edit hardware-configuration.nix
.
Create a new directory mkdir /mnt/nixos-root
. As mentioned, you may use any directory for mount - even /mnt/actual-boot
, or even one with files already! But for conventional purposes we have crated /mnt/nixos-root
.
Mount NixOS partition with mount /dev/nvme0n1p5 /mnt/nixos-root
Open up /mnt/nixos-root/etc/nixos/hardware-configuration.nix
in your editor of choice (if you were booted to NixOS, the path would have been /etc/nixos/hardware-configuration.nix
).
Locate a similarly-looking piece of code:
fileSystems."/boot" =
{ device = "/dev/disk/by-uuid/3C5B-FCD0";
fsType = "vfat";
};
This is the relevant snippet that tells NixOS where to search for Boot partition. uuid
stands for "Universally Unique Identifier" - and, as name may suggest, it uniquely identifies a partiton (a disk) from the rest. Since we're using the Systemd Bootloader (the default one in NixOS), it stores versions of Linux kernel that NixOS boots with on the Boot partition, and not on NixOS partition. The development of Linux never stops, thus the kernels are being updated frequently, and when you perform an upgrade to your NixOS system, you'll very likely to land on a newer kernel as well. Taking into account that Initrd and 2 Linux kernels have a combined size nearing 100 MiB at the time of writing, it is no surprise 100 MiB is too small for a Boot partition! And that's why we had to resize the Boot partition in the first place. If Systemd tries to store more than 2 kernels, e.g. you have performed NixOS upgrades 3 times pulling a different kernel versions each time, 3rd definitely won't fit, and it will break either Windows or NixOS boot process, with the latter being more likely.
Finale
After so much ado - and we're finally done! You can now safely reboot into either Windows or NixOS. Good luck!
You inspire me to keep writing. Every reader counts.