CLI tool
raspberrypi/rpi-image-gen avatar
raspberrypi/rpi-image-gen

rpi-image-gen: custom Raspberry Pi images built from YAML configs and layers

A tool to generate highly customised software images for Raspberry Pi devices.

953 stars125 forksPythonBSD-3-Clause

At a glance

What is it?
rpi-image-gen builds reproducible disk images for Raspberry Pi devices from declarative YAML configuration, using bdebstrap, mmdebstrap and genimage. It is not the tool that builds Raspberry Pi OS itself, and it only runs on a narrow set of Debian arm64 hosts.
Who is it for?
Adopt rpi-image-gen when you ship devices and need images you can rebuild, audit and customise: an image per product variant, signed boot with encrypted filesystems, or a software bill of materials for the people who consume it.
Can I use it commercially?
Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Not the OS build, the per-device image build

The first thing the README does is set a boundary. rpi-image-gen is a tool for creating custom software images for Raspberry Pi devices, and for the tool used to create the Raspberry Pi OS distribution you should go to the pi-gen repository instead.

That distinction matters because the two projects answer different questions. The distribution build produces the image Raspberry Pi publishes. This tool produces an image for your product, built on the same foundations, with your filesystem configuration, your packages and your provisioning.

The positioning is also about where it runs. The README states that it runs best on a Raspberry Pi Host running up-to-date 64-bit Raspberry Pi OS, and later that it is developed on Raspberry Pi OS with Debian Bookworm and Trixie arm64 as the supported native hosts. The homepage points at raspberrypi.com, and the tool is BSD-3-Clause licensed with the LICENSE file at the repository root.

The project is described as under active development, with issues to be reported in the repository and feature suggestions welcome. The repository is not archived and the last push was on 2026-10-19, with releases v2.8.0 tagged as Traits on 2026-08-13, v2.7.0 on 2026-06-26 and v2.6.0 on 2026-05-22.

A first build from a config file

The quick start is a clone, a dependency install and one build command:

bash
git clone https://github.com/raspberrypi/rpi-image-gen.git
cd rpi-image-gen
sudo ./install_deps.sh
./rpi-image-gen build -c ./config/trixie-minbase.yaml

The result is a device image at ./work/image-deb13-arm64-min/deb13-arm64-min.img. You then write it to an SD card with Raspberry Pi Imager, either through the GUI where you select Use Custom, or from the command line:

bash
sudo rpi-imager --cli ./work/image-deb13-arm64-min/deb13-arm64-min.img /dev/mmcblk0

One detail deserves attention before you flash anything. The README notes that this image intentionally has login passwords disabled. That is a deliberate property of the example configuration rather than a bug, but it means the default output is not a device you want reachable on a network without provisioning it first.

The README also points at other installation routes for the same image: rpiboot with the pi-gen-micro fastboot gadget for USB mass storage or fastboot, and provisioning with rpi-sb-provisioner. Both are separate repositories with their own documentation, which tells you how much of the surrounding tooling this project deliberately leaves to other tools.

Configurations, layers and hooks

Three concepts carry the design, and the README states them as a core concepts list.

Configuration means declaring variables and build attributes in simple, easy to read files. The format is YAML, and the config directory at the repository root holds the shipped configurations, including the trixie-minbase one used in the quick start.

Layers are modular, composable components with automatic variable checking, validation policies and comprehensive documentation. A layer is a unit of the filesystem and of the build logic, and the layer directory is described as the layer library, with layer-hooks holding the common hooks used by it. The CLI exposes them: rpi-image-gen layer --list enumerates every available layer, and rpi-image-gen layer --describe my-layer explains one.

Hooks are shell scripts that run at defined points in the build process, and the builtin directory holds built-in hooks and helper tooling.

The separation of build logic from target hardware specifics is the point of the whole structure. The tool is described as producing bootable disk images, partitioned media layouts and device-agnostic filesystem tarballs, and it integrates package management, filesystem assembly and image layout definition. That is what lets the same build definition produce a disk image for a device, a tarball for a container, or an artefact for a CI job, and the examples directory shows exactly those shapes, including docker_export, oci_create, container_chroot, ota, signed_ota, mass_storage_gadget and nested_image.

bdebstrap, mmdebstrap, genimage and podman unshare

The architecture section names the tools underneath, and it is worth knowing what each one does because the failure modes differ.

bdebstrap handles modular layer application, mmdebstrap constructs the filesystem, and genimage creates the disk image. YAML carries the configuration. And podman unshare is used to handle filesystem ownership correctly using Linux namespaces.

That last point is the reason for the unusual privilege requirements. The README explains that the build invokes mmdebstrap to create a chroot and mounts pseudo-filesystems, proc, sysfs and devpts, inside a private mount namespace. That requires CAP_SYS_ADMIN or an equivalent, for example --privileged or --security-opt=unconfined depending on the rootless or container setup, and the README states plainly that the build will fail without that capability.

The tool itself runs as a regular user and does not require root privileges, which sounds contradictory until you read the mount namespace detail. The user-space process asks podman for a user namespace in which it holds the capabilities it needs, and the chroot and pseudo-filesystem mounts happen inside that namespace rather than on the host.

There is also a note about building its own copies of critical host tools. The tool builds them into a private sysroot so it always has current, fully featured versions and can support architectures the workstation distribution might not package. The trade-off, as the README puts it, is a small one-time build delay plus additional native dependencies, and the sysroot is reusable across builds.

The supported host matrix is narrow and stated plainly

The Important section of the README is the part to read before choosing a machine to build on.

rpi-image-gen is developed on Raspberry Pi OS, with Debian Bookworm and Trixie arm64 as the supported native hosts. It expects a Debian-based system and can run in containers or on non-arm64 hosts via QEMU, but those environments are not formally supported. Other environments may succeed if granted the necessary privileges, but remain outside the scope of support. For a supported path, run on native Debian Bookworm or Trixie arm64.

That is an unusually explicit statement of scope, and it is the reason to read the docs rather than assume. In practice it means a developer laptop running Ubuntu or macOS is not a supported builder, and a CI runner on x86 is not a supported builder, even though both may work. For a team that wants reproducible images, the safe reading is that the build host is part of the build contract, and it should be a pinned arm64 Debian machine or a container with the right capabilities.

The dependency list is a file, the depends file, which the README points to for the complete list of required packages, and install_deps.sh installs them.

Why use it instead of the official distribution

The Why use this section lists the reasons, and they are worth reading as the project's actual argument.

Fast builds, because it uses pre-built packages instead of building from source. Production-ready, because the same binaries are used by millions in production worldwide. Compatible, because it uses the same library versions as Raspberry Pi OS. Customisable, because you configure the filesystem exactly as needed. Secure, through integration with rpi-sb-provisioner to automatically set up signed boot and encrypted filesystems. And auditable, by generating a software bill of materials and CVE reports to give consumers of your image confidence.

The last two are the differentiators against the general practice of building a device image by copying an official image and installing packages on it. That approach is fast to start and produces an artefact nobody can account for. Here the image is a declared input, and the output can carry a bill of materials and a vulnerability report, which is what a customer, an auditor or a security reviewer asks for.

For the reader, the honest framing is that this is build infrastructure for hardware products, not a hobby tool. Its audience is the person who has to ship the same device image many times and has to answer questions about it afterwards.

Documentation that matches your local version

The documentation setup is worth a note because it solves a problem most projects ignore.

The published documentation lives at raspberrypi.github.io/rpi-image-gen, but it may not match the version you have installed. The README gives you a way around that: rpi-image-gen docs browses docs matching your local version. It starts a web server on port 3142, or on the port given as an argument, so rpi-image-gen docs 9000 serves on a different one, and you point your browser at the URL printed on startup.

Inside the repository, docs/index.adoc is the comprehensive reference for the configuration system, layer management, metadata, variable validation, provisioning and execution flow, and getting_started.adoc plus the examples directory cover customisation and usage. The directory listing in the README maps out the rest: bin for common executables, config for configuration files, contrib for optional community-maintained extensions outside the supported core, device for device specific assets, image for disk layout assets, keydir for cryptographic assets, lib for execution helpers and macros, package for build recipes, site for the core Python engine classes, templates for templating assets such as doc generation, test for the test harness, and trait for built-in trait token definitions described as the hardware and boot capability hierarchy.

The trait directory and the v2.8.0 release named Traits point the same way: hardware capability is a declared token set rather than a property you discover at build time.

Editorial conclusion

Adopt rpi-image-gen when you ship devices and need images you can rebuild, audit and customise: an image per product variant, signed boot with encrypted filesystems, or a software bill of materials for the people who consume it. Do not adopt it to produce Raspberry Pi OS itself, since the README points that work at the pi-gen repository, and do not expect it to run on your laptop, since the supported hosts are Debian Bookworm and Trixie on arm64 and anything else is out of scope even if it happens to work. Verify first that the host you have is one of those two, that the container or CI runner you plan to use grants CAP_SYS_ADMIN or the equivalent, because the build will fail without it, and that the image you produce does not ship with login passwords enabled, since the README states that the example image intentionally has them disabled.

Frequently asked questions

How do I build a Raspberry Pi image with rpi-image-gen?

Clone the repository, run sudo ./install_deps.sh, then run ./rpi-image-gen build -c ./config/trixie-minbase.yaml. The resulting device image is written to the work directory, for example ./work/image-deb13-arm64-min/deb13-arm64-min.img.

Can I write the rpi-image-gen image to an SD card from the command line?

Yes. The README gives sudo rpi-imager --cli with the image path and the device, for example sudo rpi-imager --cli ./work/image-deb13-arm64-min/deb13-arm64-min.img /dev/mmcblk0. In the Imager GUI you select Use Custom instead.

What host operating systems does rpi-image-gen support?

The supported native hosts are Debian Bookworm and Trixie on arm64, developed on Raspberry Pi OS. It can run in containers or on non-arm64 hosts via QEMU, but the README states those environments are not formally supported.

Why does the rpi-image-gen build fail in a container?

The build invokes mmdebstrap to create a chroot and mounts pseudo-filesystems inside a private mount namespace, which requires CAP_SYS_ADMIN or an equivalent such as --privileged or --security-opt=unconfined. The README states the build will fail without that capability.

How do I see the documentation for my local rpi-image-gen version?

Run rpi-image-gen docs, which starts a web server on port 3142, or pass a different port such as rpi-image-gen docs 9000, and open the URL printed on startup.

Official sources

  1. License: BSD-3-Clause
  2. Project website
  3. raspberrypi/rpi-image-gen on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/raspberrypi-rpi-image-gen.svg)](https://hysenlabs.com/projects/raspberrypi-rpi-image-gen)

Was this useful?