distrobuilder: building LXC and Incus images from a YAML recipe
System container image builder for LXC and Incus
At a glance
- What is it?
- distrobuilder is the Go tool that turns a distribution manifest into a root filesystem and then an Incus or LXC image, with a pack path for images you already have and a Windows ISO repack command. It suits platform teams who need reproducible system container and VM images across distributions.
- Who is it for?
- distrobuilder is a good fit for a platform team that publishes system container images for several distributions and wants the build defined in one reviewed YAML file rather than in a pile of shell scripts, and for anyone who needs to turn an existing root filesystem into an Incus or LXC image.
- Can I use it commercially?
- Yes. Apache-2.0 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 7 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Seven commands, and the split between building and packing
The command surface is short enough to read in one screen, and the way it is organised tells you how the tool thinks. The help output lists build-dir to build a plain rootfs, build-incus and build-lxc to build an image from scratch for each runtime, pack-incus and pack-lxc to create an image from an existing rootfs, and repack-windows to repack a Windows ISO with drivers included. So there are two halves. The build commands do the work of constructing a root filesystem from a manifest, and the pack commands take a root filesystem you already have and wrap it in the image format the runtime expects. That second half is the one that is easy to overlook and often the one you want, because the slow part of building an image is the distribution bootstrap and the fast part is the packaging, and if you have a rootfs from a virtual machine or from an existing pipeline, pack is all you need. The global flags are the standard ones, with a cache directory that is cleaned up by default, a debug switch, a timeout, an options override taking a list of key=value pairs, and a flag to disable the use of filesystem overlays, which matters when the build has to run somewhere the kernel will not cooperate with overlay mounts.
Installing it as a snap or from source
There is a package route and a source route. The package is available from the Snap Store and installs with the classic flag, which is needed because the tool reaches into the host to run debootstrap and to mount things:
sudo snap install distrobuilder --classicBuilding from source needs Go and a set of host tools, and the documentation gives the exact list per distribution family. The Debian-based list is the most complete, with golang-go, gcc, debootstrap, rsync, gpg, squashfs-tools, git, make, build-essential, and the Windows specific tools libwin-hivex-perl, wimtools and genisoimage. The Arch list swaps in the equivalent packages including hivex, cdrtools and wimlib, and the Red Hat list uses dnf with gnupg2, hivex and genisoimage. The version requirement is Go 1.21 or higher, with a pointer to the upstream install page if your distribution does not have a recent enough version. The source build itself is a clone into the Go workspace followed by make, which produces the binary in the Go bin directory, and the documentation reminds you that you can add that directory to your PATH so you do not have to invoke the full path.
VM images need a different set of host tools
The runtime dependencies split is the detail that catches people out. If you intend to build Incus VM images, using the build-incus command with the vm option, the host needs more than the container path does. The Debian-based instructions add btrfs-progs, dosfstools and qemu-kvm on top of the base set. That makes sense from what the operation does, since a virtual machine disk has to be created, partitioned and formatted rather than assembled as a tarball, and the Incus runtime then boots that disk. It also means the tool is not self-contained in the way a pure Go program could be, and the practical consequence is that a build machine for VM images is a different machine from a build machine for containers, or at least a different base image. The documentation does not spell out the requirement for other distribution families in the visible part, so on a non-Debian host the equivalent packages have to be identified by name, which is the sort of thing that turns into a half hour of trial and error.
A Go module that reaches into the container and image ecosystem
The dependency list in the go.mod tells you what the tool actually does, and it is broader than a Go program that writes tarballs. The module path carries a major version, github.com/lxc/distrobuilder/v3, and the go directive asks for a recent Go release. The Incus runtime itself is a direct dependency at version 7.3.0, which is the signal that this tool is part of the same family as the runtime it produces images for, and the OCI image specification and umoci are there for the image format. Podman's image library appears as a direct dependency, and the image spec, umoci and the containers libraries together suggest the tool can talk to several image backends rather than only producing one format. There is also a Windows file handling library, go-winio, which pairs with the repack-windows command and the hivex and wimtools host packages, because a Windows image needs the registry hives and the Windows imaging format handled rather than a Linux rootfs. The command line is built with cobra, the configuration is YAML, the templating is pongo2, the logging is logrus, and HTML parsing for release notes or similar content uses htmlquery.
The Makefile shows how the project ships and tests
The build system has a few things in it that tell you how the project is run. The default target formats the source with gofmt and then runs go install across the packages, echoing that distrobuilder built successfully. The check target depends on the default and runs the tests with sudo, which is unusual and tells you something, because the test suite needs root to do things like mount and to run debootstrap in a chroot. The build flags exported by the Makefile are the interesting part, since they set three build tags for the container image storage backends, a Docker daemon stub, a containers image storage stub and an OpenPGP stub, which is the standard way of compiling the containers image library without pulling in a real storage backend or a real signing implementation. The dist target assembles a release tarball by exporting the git tree with a prefix, vendoring the dependencies inside it, and packing the result, so the released tarball is self contained. The update-gomod target pins a specific version of the sigstore fulcio tool and then tidies the module file against the declared Go version. The documentation build has its own targets with a Python virtual environment for Sphinx.
Where the images are meant to end up
The project belongs to the Linux containers family, with the homepage pointing at linuxcontainers.org, and the repository topics list containers, images, incus, lxc and virtual-machines, which is the full spread of what it produces. The value of the tool is that the image definition is a reviewed file. A manifest naming a distribution, a release, the packages to include, the files to copy in and the run commands to execute is something you can put in version control, review and reproduce, and the difference from a shell script that happens to produce the same image is that the output is the same on a different build host. The how-to document is the reference for the manifest format and the documentation also has a separate troubleshooting page, and both are linked from the readme rather than reproduced in it. The project status badges point at GitHub Actions for continuous integration and the CII Best Practices badge, which is the standard marker for a project in the Linux containers space that has been through the badge process.
Editorial conclusion
distrobuilder is a good fit for a platform team that publishes system container images for several distributions and wants the build defined in one reviewed YAML file rather than in a pile of shell scripts, and for anyone who needs to turn an existing root filesystem into an Incus or LXC image. It is the wrong tool if you want a Docker or OCI application image, since this builds operating system images rather than application artefacts, and it is the wrong tool if you cannot install a set of privileged host tools, because debootstrap, rsync, squashfs-tools and the rest are build-time requirements rather than optional extras. It is also the wrong tool if you only need a VM image, since the Incus VM path needs qemu and btrfs tooling on the host. Before running it, read the how-to document, because the YAML manifest carries the whole build definition and the command names differ between the from-scratch and pack paths. The project is Apache-2.0 licensed, the last push was on 2026-10-16, and the current release is v3.4.0 from 2026-09-29.
Frequently asked questions
What is distrobuilder and what does it build?
It is a Go system container and VM image builder for Incus and LXC, used to create container images for both runtimes. The commands are build-dir for a plain rootfs, build-incus and build-lxc to build an image from scratch, pack-incus and pack-lxc to package an existing rootfs, and repack-windows to repack a Windows ISO with drivers included.
How do I install distrobuilder?
From the Snap Store with sudo snap install distrobuilder --classic. From source you need Go 1.21 or newer plus host tools, which are listed per distribution family, and the build is a clone followed by make, producing the binary in the Go bin directory. Go 1.21 or higher is the stated requirement.
What extra tools do I need to build Incus VM images?
The build-incus command with the vm option needs more than the container path does. On Debian-based systems you add btrfs-progs, dosfstools and qemu-kvm to the base set of golang-go, gcc, debootstrap, rsync, gpg, squashfs-tools, git, make and build-essential.
What is the difference between the build and pack commands in distrobuilder?
The build commands construct a root filesystem from a manifest and then package it, while the pack commands take a rootfs you already have and create the Incus or LXC image from it. That split lets you skip the slow distribution bootstrap when you already have a root filesystem from somewhere else.
How is distrobuilder licensed and released?
The project is licensed under Apache-2.0, and the module path is github.com/lxc/distrobuilder/v3. The Makefile assembles a self contained release tarball by vendoring the dependencies into the exported tree, and the most recent release is v3.4.0 from 2026-09-29 with the last push on 2026-10-16.
Official sources
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.
[](https://hysenlabs.com/projects/lxc-distrobuilder)Was this useful?