Arch Linux

Manually Add Menu Entry to GRUB on Arch Linux

GRUB (Grand Unified Bootloader) is the default boot loader for most Linux distributions, including Arch Linux. While GRUB’s os-prober can detect other operating systems automatically, it does not always work – especially with custom Linux installations, Windows on separate drives, or ISO files you want to boot directly. Adding custom GRUB menu entries gives you full control over your boot process for dual-boot setups, recovery environments, and ISO booting.

Original content from computingforgeeks.com - post 48

This guide walks through adding custom menu entries to GRUB on Arch Linux. We cover entries for Windows, other Linux distributions, ISO images, and rescue/recovery modes. Every example uses the /etc/grub.d/40_custom file, which is the correct place for user-defined entries that survive GRUB updates. For full reference, see the Arch Wiki GRUB page.

Prerequisites

  • A running Arch Linux system with GRUB already installed and working
  • Root or sudo access
  • Basic knowledge of your disk layout – partition UUIDs and filesystem types
  • For dual-boot entries: the UUID of the target partition (obtained with blkid)
  • For ISO boot entries: an ISO file stored on a local partition

Step 1: Understand GRUB Config Structure

GRUB’s configuration lives in /boot/grub/grub.cfg, but you should never edit that file directly. It gets regenerated every time you run grub-mkconfig. Instead, GRUB uses scripts in /etc/grub.d/ to build the final config. Here is what each file does:

  • 00_header – Sets global defaults (timeout, default entry, colors)
  • 10_linux – Auto-detects Linux kernels on the current system
  • 20_linux_xen – Xen hypervisor entries
  • 30_os-prober – Auto-detects other operating systems (Windows, other Linux installs)
  • 40_custom – Your custom entries go here
  • 41_custom – Sources additional config from a separate file

List the scripts currently in /etc/grub.d/ to confirm the structure on your system:

ls -la /etc/grub.d/

You should see executable scripts numbered in order. GRUB processes them sequentially, so entries in 40_custom appear after the auto-detected entries:

total 80
drwxr-xr-x 2 root root 4096 Mar 22 10:00 .
drwxr-xr-x 4 root root 4096 Mar 22 10:00 ..
-rwxr-xr-x 1 root root 10627 Jan 15 12:30 00_header
-rwxr-xr-x 1 root root 18683 Jan 15 12:30 10_linux
-rwxr-xr-x 1 root root 14180 Jan 15 12:30 20_linux_xen
-rwxr-xr-x 1 root root 14400 Jan 15 12:30 30_os-prober
-rwxr-xr-x 1 root root   214 Jan 15 12:30 40_custom
-rwxr-xr-x 1 root root   215 Jan 15 12:30 41_custom
-rw-r--r-- 1 root root   483 Jan 15 12:30 README

The key takeaway: always add custom entries to 40_custom. This file persists across GRUB package updates, so your entries are safe.

Step 2: Add a Custom GRUB Menu Entry in /etc/grub.d/40_custom

Before adding any entry, you need the UUID of the target partition. Run blkid to list all partitions and their UUIDs:

sudo blkid

The output lists every block device with its UUID, filesystem type, and label. Identify the root partition of the OS you want to boot:

/dev/sda1: UUID="A1B2-C3D4" BLOCK_SIZE="512" TYPE="vfat" PARTLABEL="EFI" PARTUUID="abcd1234-01"
/dev/sda2: UUID="f47ac10b-58cc-4372-a567-0e02b2c3d479" BLOCK_SIZE="4096" TYPE="ext4" PARTUUID="abcd1234-02"
/dev/sdb1: UUID="842a7abb-3547-4504-a9f8-bfbc479a3f0e" BLOCK_SIZE="4096" TYPE="ext4" PARTUUID="efgh5678-01"

In this example, /dev/sdb1 with UUID 842a7abb-3547-4504-a9f8-bfbc479a3f0e is the root partition of the second Linux installation. Write down the UUID – you need it for the menu entry. Now open the custom GRUB config file:

sudo vim /etc/grub.d/40_custom

Add a new menu entry below the existing comments. Here is an example for booting another Linux distribution (Gentoo in this case) from a separate partition:

#!/bin/sh
exec tail -n +3 $0

menuentry "Gentoo Linux" {
    search --set=root --fs-uuid 842a7abb-3547-4504-a9f8-bfbc479a3f0e
    linux /boot/vmlinuz-6.12-gentoo root=UUID=842a7abb-3547-4504-a9f8-bfbc479a3f0e rw quiet
    initrd /boot/initramfs-6.12-gentoo.img
}

Replace the UUID with the actual UUID from your blkid output. The search --set=root --fs-uuid line tells GRUB which partition to use. The linux line specifies the kernel path on that partition, and initrd loads the initial ramdisk. Mount the target partition first to verify the exact kernel filename under its /boot directory.

Step 3: Add a Windows Boot Entry to GRUB

Windows uses its own bootloader (the Windows Boot Manager) stored on the EFI System Partition. You do not load a Linux kernel for Windows – instead, you chainload the Windows EFI bootloader. First, find the UUID of your EFI partition:

sudo blkid | grep -i vfat

Look for the partition with TYPE=”vfat” – that is typically the EFI System Partition. Note its UUID (the short format like A1B2-C3D4). Open the custom file:

sudo vim /etc/grub.d/40_custom

Add the Windows chainload entry. For UEFI systems (most modern hardware), use this format:

menuentry "Windows 11" {
    insmod part_gpt
    insmod fat
    insmod chain
    search --set=root --fs-uuid A1B2-C3D4
    chainloader /EFI/Microsoft/Boot/bootmgfw.efi
}

Replace A1B2-C3D4 with your actual EFI partition UUID. The insmod lines load the required GRUB modules for GPT partitions, FAT filesystem, and chainloading. For legacy BIOS systems (MBR partitioning), the entry looks different:

menuentry "Windows 11 (Legacy BIOS)" {
    insmod part_msdos
    insmod ntfs
    insmod chain
    search --set=root --fs-uuid ABCD1234EFGH5678
    chainloader +1
}

On legacy BIOS, chainloader +1 loads the first sector of the Windows partition. Use the NTFS partition UUID (the long hex string from blkid) in this case.

Step 4: Add Another Linux Distro Entry

Adding a second Linux distribution follows the same pattern as Step 2. The key information you need is the UUID of that distro’s root partition and the kernel filename. Mount the other distro’s root partition to check:

sudo mkdir -p /mnt/other-linux
sudo mount /dev/sdb1 /mnt/other-linux
ls /mnt/other-linux/boot/vmlinuz*

This shows the available kernel images on that partition. Note the exact filename. Here is an example entry for Ubuntu installed on a separate partition:

menuentry "Ubuntu 24.04" {
    search --set=root --fs-uuid d3f8a92c-1234-5678-abcd-ef0123456789
    linux /boot/vmlinuz-6.8.0-45-generic root=UUID=d3f8a92c-1234-5678-abcd-ef0123456789 rw quiet splash
    initrd /boot/initrd.img-6.8.0-45-generic
}

Each distribution names its kernel and initrd files differently. Ubuntu uses vmlinuz-VERSION-generic and initrd.img-VERSION-generic. Fedora uses vmlinuz-VERSION.fc42.x86_64. Always check the actual filenames. After verifying, unmount the partition:

sudo umount /mnt/other-linux

If the other Linux distro uses a separate /boot partition, you need to search for that partition’s UUID instead and adjust the kernel path accordingly (the path becomes /vmlinuz-* since /boot is the root of that partition).

Step 5: Add an ISO Boot Entry

GRUB can boot ISO images directly from a local partition using the loopback command. This is useful for keeping live distributions or rescue tools available without burning them to USB. Store the ISO on a partition that GRUB can read (ext4, FAT32, or NTFS). For this example, the ISO is at /iso/archlinux-2026.03.01-x86_64.iso on the root partition.

sudo vim /etc/grub.d/40_custom

Add the following entry for booting an Arch Linux ISO. The loopback command mounts the ISO as a virtual device:

menuentry "Arch Linux ISO" {
    set isofile="/iso/archlinux-2026.03.01-x86_64.iso"
    search --set=root --fs-uuid f47ac10b-58cc-4372-a567-0e02b2c3d479
    loopback loop $isofile
    linux (loop)/arch/boot/x86_64/vmlinuz-linux img_dev=/dev/disk/by-uuid/f47ac10b-58cc-4372-a567-0e02b2c3d479 img_loop=$isofile earlymodules=loop
    initrd (loop)/arch/boot/x86_64/initramfs-linux.img
}

The loopback loop $isofile line makes GRUB treat the ISO as a block device named (loop). The kernel parameters img_dev and img_loop tell the Arch initramfs where to find the ISO at boot time. Different distributions require different kernel parameters for ISO booting – check each distro’s documentation for the correct values.

Step 6: Add a Recovery/Rescue Entry

A recovery entry boots your Arch Linux kernel into a minimal environment, useful when something breaks. You can boot into single-user mode (init level 1) or drop directly to a root shell. This does not need a separate partition – it uses your existing Arch kernel with different boot parameters.

sudo vim /etc/grub.d/40_custom

Add these recovery entries. The first boots into single-user mode (systemd rescue.target), and the second drops to an emergency shell before any services start:

menuentry "Arch Linux - Rescue Mode" {
    search --set=root --fs-uuid f47ac10b-58cc-4372-a567-0e02b2c3d479
    linux /boot/vmlinuz-linux root=UUID=f47ac10b-58cc-4372-a567-0e02b2c3d479 rw systemd.unit=rescue.target
    initrd /boot/initramfs-linux.img
}

menuentry "Arch Linux - Emergency Shell" {
    search --set=root --fs-uuid f47ac10b-58cc-4372-a567-0e02b2c3d479
    linux /boot/vmlinuz-linux root=UUID=f47ac10b-58cc-4372-a567-0e02b2c3d479 rw systemd.unit=emergency.target
    initrd /boot/initramfs-linux.img
}

The difference between the two: rescue.target mounts filesystems and starts a minimal set of services, giving you a single-user root shell with your filesystems available. emergency.target does almost nothing – it mounts the root filesystem read-only and drops you into a shell immediately, which is what you need when systemd itself is broken. For more on booting Linux into emergency and recovery mode, see our dedicated guide.

Step 7: Regenerate grub.cfg with grub-mkconfig

After adding all your custom entries to /etc/grub.d/40_custom, regenerate the GRUB configuration file. This reads all scripts in /etc/grub.d/ and produces the final /boot/grub/grub.cfg:

sudo grub-mkconfig -o /boot/grub/grub.cfg

The output should confirm that your custom entries were found. Look for lines mentioning your custom menu entries:

Generating grub.cfg ...
Found linux image: /boot/vmlinuz-linux
Found initrd image: /boot/initramfs-linux.img
Found fallback initrd image(s) in /boot: initramfs-linux-fallback.img
Warning: os-prober will not be executed to detect other bootable partitions.
Systems on them will not be added to the GRUB boot configuration.
Check GRUB_DISABLE_OS_PROBER documentation entry.
Adding custom menu entries ...
done

The “Adding custom menu entries …” line confirms GRUB picked up your 40_custom entries. Verify the generated config includes your entries by checking the end of the file:

grep "menuentry" /boot/grub/grub.cfg

This lists all menu entries in the final config. Confirm each of your custom entries appears in the output before rebooting.

Step 8: Configure GRUB Defaults in /etc/default/grub

The /etc/default/grub file controls GRUB’s behavior – timeout duration, default boot entry, kernel parameters, and more. Open it to review and adjust settings:

sudo vim /etc/default/grub

Here are the most useful settings for a multi-boot system:

# Boot the last selected entry by default
GRUB_DEFAULT=saved
GRUB_SAVEDEFAULT=true

# Show the menu for 10 seconds before auto-booting
GRUB_TIMEOUT=10

# Show the menu (not hidden)
GRUB_TIMEOUT_STYLE=menu

# Default kernel parameters for Linux entries
GRUB_CMDLINE_LINUX_DEFAULT="loglevel=3 quiet"
GRUB_CMDLINE_LINUX=""

# Enable os-prober to auto-detect other operating systems
GRUB_DISABLE_OS_PROBER=false

The key settings explained:

  • GRUB_DEFAULT=saved with GRUB_SAVEDEFAULT=true – GRUB remembers your last selection and boots it next time. Without this, it always boots the first entry
  • GRUB_TIMEOUT=10 – gives you 10 seconds to select an entry. Set to 0 for instant boot (no menu) or -1 to wait indefinitely
  • GRUB_TIMEOUT_STYLE=menu – always shows the boot menu. Use hidden to hide it (press Shift to reveal) or countdown to show a timer
  • GRUB_DISABLE_OS_PROBER=false – enables automatic detection of Windows and other operating systems. On Arch Linux, this is disabled by default since GRUB 2.06

After making changes, regenerate the config again:

sudo grub-mkconfig -o /boot/grub/grub.cfg

If you want to set a specific default entry by name instead of using saved, use the exact menu entry title. For example, GRUB_DEFAULT="Windows 11" always boots Windows first. You can also use grub-set-default to set the default from the command line without editing the file. For additional GRUB security, consider protecting GRUB with a password.

Step 9: Troubleshoot Common GRUB Issues

When custom entries do not work, the problem is usually a wrong UUID, incorrect kernel path, or missing GRUB modules. Here are the most common issues and fixes.

Entry does not appear in boot menu

If your custom entry is missing from the boot menu after running grub-mkconfig, check that the 40_custom file is executable:

ls -la /etc/grub.d/40_custom

The file must have execute permission. If it does not, fix it:

sudo chmod +x /etc/grub.d/40_custom

Then regenerate the config with sudo grub-mkconfig -o /boot/grub/grub.cfg and check again.

Error: “no such device” at boot

This means GRUB cannot find the partition with the specified UUID. Double-check the UUID by running blkid again. A common mistake is copying the PARTUUID instead of the UUID – GRUB’s search --fs-uuid needs the filesystem UUID, not the partition table UUID.

Error: “file not found” for kernel or initrd

The kernel or initrd path in your entry does not match the actual filename on disk. Mount the target partition and verify:

sudo mount /dev/sdb1 /mnt/other-linux
ls -la /mnt/other-linux/boot/

Kernel version numbers change with updates. After a kernel update on the target OS, you need to update the filename in your custom GRUB entry and regenerate the config.

Windows entry boots to a black screen

This usually means the chainloader path is wrong. Verify the Windows EFI bootloader exists on the EFI partition:

sudo mount /dev/sda1 /mnt/efi
ls /mnt/efi/EFI/Microsoft/Boot/bootmgfw.efi

If the file exists, the path is correct. If not, Windows may be installed in legacy BIOS mode, which requires a different chainloader command (see Step 3). Also confirm you are using the correct EFI partition UUID – systems with multiple drives may have more than one EFI partition.

Reinstall GRUB after it breaks

If GRUB itself is broken and you cannot boot at all, boot from an Arch Linux installation USB, mount your root and EFI partitions, chroot in, and reinstall GRUB:

mount /dev/sda2 /mnt
mount /dev/sda1 /mnt/boot/efi
arch-chroot /mnt
grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=GRUB
grub-mkconfig -o /boot/grub/grub.cfg

This reinstalls the GRUB EFI binary and regenerates the configuration, including all your custom entries from 40_custom. For creating bootable USB drives on Linux, several tools are available.

Conclusion

Custom GRUB entries in /etc/grub.d/40_custom give you precise control over multi-boot configurations on Arch Linux. Whether you are chainloading Windows, booting into another Linux distribution, loading ISO images directly, or setting up recovery entries – the process always follows the same pattern: identify the partition UUID, write the menu entry, and regenerate with grub-mkconfig.

For production systems, keep a recovery entry in your GRUB menu at all times. It takes seconds to add and can save hours when a bad kernel update or misconfigured service prevents normal boot. Also consider the official GRUB manual as reference for advanced features like theming, authentication, and scripting within GRUB entries.

Related Articles

Virtualization How To Manage Linux OS Images using qemu-img Arch Linux Download online web pages as PDF with Percollate Cheat Sheets Postfix Commands Administration Cheat Sheet Arch Linux Checking TCP Connections States in Linux with Netstat

Leave a Comment

Press ESC to close