← Learn··Updated 31 May 2026·6 min read

What the initramfs is (and what mkinitcpio does)

A beginner-friendly explainer of the initramfs: the tiny RAM-based root filesystem the kernel uses to find your real disk, and how Arch's mkinitcpio builds it.

Operating systems
Kernel & processes
#linux
#initramfs
#boot
#ai-assisted

level:Beginner

During an Arch install you generate something called the initramfs without ever really being told what it is. The wiki mentions it, pacstrap quietly builds one when it installs the kernel, and your bootloader entry points at a file called initramfs-linux.img. Most people copy the commands and move on. But the initramfs solves a genuinely clever bootstrap problem, and once you see what that problem is, the whole early boot sequence stops being a black box. This post walks through it.

The boot chain

Booting a Linux machine is a relay race. Each stage does just enough to load and start the next, then hands off:

  1. Firmware (UEFI on any modern machine) runs first, finds a bootloader on disk, and launches it.
  2. The bootloader loads two things into memory: the kernel and the initramfs. Then it starts the kernel.
  3. The kernel initialises the CPU, memory, and core drivers, then needs to find and mount your real root filesystem — the actual installed system on disk.
  4. To do that it uses the initramfs: a small temporary root filesystem already sitting in RAM, holding just enough to locate and mount the real root.
  5. Once the real root is mounted, the initramfs hands off to the real init system (systemd, PID 1), which brings up the rest of userspace.

Laid out as a single chain, the handoffs are easier to hold in your head: each box does its part and passes the baton, and the initramfs is the one box that exists purely to bridge a gap. Firmware to bootloader to kernel to a tiny RAM root, then onto the real disk and the real init.

flowchart LR
    A["firmware<br/><i>UEFI</i>"] --> B["bootloader"]
    B --> C["kernel + initramfs<br/><i>in RAM</i>"]
    C --> D["mount real root"]
    D --> E["switch_root"]
    E --> F["init<br/><i>systemd, PID 1</i>"]

Stages 1 and 2 are the bootloader's territory, covered in bootloaders: systemd-boot vs GRUB. This post is about stage 4 — the strange-sounding middle step between "kernel started" and "real system running."

This is not a Linux quirk, either: Windows and macOS run their own small early-boot environment before the full OS is up, the equivalent stepping stone between firmware and a running system. They simply keep it implicit and out of sight, where Arch hands you the file and the command that builds it.

What the initramfs is

The initramfs ("initial RAM filesystem") is a small, self-contained root filesystem that the bootloader loads into memory alongside the kernel. The kernel unpacks it into RAM and runs it as a temporary root before your real disk is mounted. Inside it lives a minimal userspace: a few essential tools and the kernel modules (drivers) needed to reach your storage. Its entire job is to find the real root filesystem, mount it, and then get out of the way — handing control to the init system on the real root and freeing the RAM it occupied.

If that sounds like an unnecessary detour, here is the problem it solves.

Why it exists: the chicken-and-egg problem

The kernel needs to read your root filesystem to boot. But the driver it needs to read that filesystem may itself live on that filesystem — the very disk it cannot yet reach. That is the chicken-and-egg trap. The kernel ships with only a small set of always-built-in drivers; everything else is a loadable module stored on disk. If your disk controller's driver is one of those modules, the kernel cannot read the disk to get the driver it needs to read the disk.

Drawn out, the loop is obvious — and so is the way out. The kernel can always reach RAM, so the bootloader pre-loads the missing piece there; the initramfs is that piece. The driver to read the disk is on the disk, so it rides in RAM instead.

flowchart TD
    A["kernel wants to mount root"] --> B{"is the disk driver<br/>built in?"}
    B -->|"yes"| C["mount real root directly"]
    B -->|"no"| D["driver lives on the disk<br/><i>the kernel cannot read yet</i>"]
    D --> E["initramfs in RAM<br/>carries the driver"]
    E --> C

The initramfs breaks the loop. The bootloader places it in RAM, where the kernel can reach it with no disk access at all. It carries exactly the drivers and tools needed to bridge from "kernel running" to "real root mounted." This matters most when the real root is anything more complex than a plain partition. As the Linux kernel documentation and Gentoo's early userspace notes spell out, the root device may be:

  • behind disk-controller drivers that ship as modules, not built in,
  • a LUKS-encrypted volume that has to be unlocked with a passphrase first,
  • an LVM logical volume or a software RAID array that must be assembled before it even appears as a device,
  • or located over the network, needing an interface configured before it can be reached.

None of that can happen inside the bare kernel. It needs a little userspace — tools that prompt for a passphrase, scan for LVM volumes, assemble the RAID. That "early userspace" is precisely what the initramfs provides. When it finishes, it performs a switch_root: it swaps the root mount to the now-mounted real disk, frees its own RAM, and executes the real /sbin/init. After that moment, the initramfs is gone and the real system is running.

Even on a dead-simple single-partition install with no encryption, Arch still uses an initramfs — partly for that disk-driver-as-module case, and partly because it is the standard, uniform path that handles the simple and the complex setups the same way.

What mkinitcpio is

The initramfs is not written by hand; it is generated from your current kernel, modules, and configuration. On Arch the default generator is mkinitcpio ("make initial cpio," named for the cpio archive format the image uses). It assembles the right modules and tools into the image that your bootloader loads.

HOOKS: what goes in the image

mkinitcpio's central concept is the HOOKS array in /etc/mkinitcpio.conf. Each hook is a building block that adds a specific capability — and crucially, hook order matters, because they run in sequence during early boot. The defaults handle a normal setup; you edit the array when your storage needs early-userspace help. For example:

  • the keyboard and keymap hooks let you type a passphrase before the real system loads,
  • the encrypt hook adds LUKS unlocking,
  • the lvm2 hook assembles LVM volumes,
  • the mdadm_udev hook assembles software RAID.

There are also two broad styles, selected by whether the systemd hook is present in the array: the traditional busybox-based early userspace, or a systemd-based one. The mkinitcpio wiki page documents the full list. For a standard install you never touch this; you only edit HOOKS when you set up encryption, LVM, or RAID and the real root needs help being found.

💡 Tip For a standard single-partition install you do nothing here — the default HOOKS already cover it. Only edit the array when you add encryption, LVM, or RAID.

When you regenerate it

After changing /etc/mkinitcpio.conf — adding a hook for encryption, say — you rebuild the image. The command that regenerates the initramfs for every installed kernel, using their preset files, is:

mkinitcpio -P

The -P (--allpresets) switch rebuilds from all presets in /etc/mkinitcpio.d/, which is what you want after a config change so no kernel is left with a stale image.

Here is the reassuring part: most of the time you never run this manually. Arch installs pacman hooks that fire automatically whenever a kernel is installed or upgraded — they call mkinitcpio for you and rebuild the matching image. That is why a routine pacman -Syu that updates your kernel "just works": the initramfs was quietly regenerated as part of the transaction. You only invoke mkinitcpio -P by hand after editing the configuration yourself.

ℹ️ Note mkinitcpio usually runs automatically — pacman regenerates the initramfs whenever you install or upgrade a kernel. You only run it yourself after changing the config (adding a hook for encryption, LVM, or RAID).

mkinitcpio is not the only choice

mkinitcpio is the Arch default, but not the only generator. The main alternative is dracut, the generator used by Fedora, RHEL, and Debian-family distributions. Dracut leans on autodetection and typically needs little to no configuration even for setups like LVM-on-LUKS, and it can produce EFI-executable images that systemd-boot detects without a manual bootloader entry. There is also Booster, a faster minimal generator. They all produce the same kind of artefact — an initramfs the bootloader hands to the kernel — and differ mainly in configuration style and features. On a fresh Arch install you will be using mkinitcpio unless you deliberately switch.

Where you meet this in the Arch install

The initramfs appears in part 2 of the install: pacstrap builds one automatically when it installs the kernel, so a standard install needs no action there, and the post notes you only run mkinitcpio -P if you change the generator config. Your bootloader entry then references the generated image with a line like initrd /initramfs-linux.img, which connects directly to the bootloader stage covered in bootloaders: systemd-boot vs GRUB. The full sequence sits in the Arch install companion.

A short close

The initramfs is the bridge across a bootstrap gap: the kernel needs to read your root filesystem, but the driver to read it might live on that very filesystem. So the bootloader loads a tiny temporary root into RAM, the kernel runs it, that early userspace finds and mounts the real disk — unlocking encryption or assembling RAID along the way — and then hands off to the real init system and disappears. mkinitcpio is the tool that builds this image on Arch, HOOKS decide what capabilities it carries, and pacman regenerates it for you on kernel updates so you rarely think about it. Now when you see initramfs-linux.img in a boot entry, you know exactly what that file is and why it has to exist.