by anglesideangle | 2026-02-28 18:39:15+00:00
I often see bootc and/or buildstream uncritically presented as the future of the linux desktop, and find it somewhat surprising because, in my experience, they are both more complex _and_ less capable than nixos.

To elaborate, I will separate linux operating systems into three categories:

1. traditional mutable package management (debian, fedora, arch, etc) - Bad model for obvious reasons, I won't get into this.

2. immutable images (embedded deployments, android, chromeos) - A build system (yocto, nix, buildroot, buildstream) procudes a disk image. System boots the disk image and handles updates using A/B root partitions with `systemd-sysupdate` or similar.

3. store-based atomic (nixos, ublue) - The system keeps a mutable store of hashed objects (/nix/store, /var/lib/containers/storage, /ostree/repo) and boots a specific system generation. Updates add new objects to the store, which must be automatically cleaned, and create a new systemd generation to boot into.

In the case of categories 2 and 3, a build system of some kind is used to produce the image or packages that are turned into the new system generation.

The bootc project, which falls into category 3, attempts to use the standardized and highly adopted OCI image format (layered filesystem changes stored in a content addressed store) as a medium for distributing linux systems. The major limitation here is that these systems are very complicated to build and extend. While it may not seem that way compared to nixos if you have prior experience writing dockerfiles, configuring your system with imperative statements that build on previous state is _really_ tedious. For example, you can't just re-use work with multiple `FROM` statements in the same layer, so you instead need to copy files between images. This is incredibly jank, look at [the docs](https://blue-build.org/how-to/minimal-setup/) for bluebuild's module system. Additionally, for a motivated user to change their system internals, they need to make the jump to hosting it with CI and pulling the images.

As jcastro mentioned elsewhere in this thread, there is work in the ublue project, which focuses on bootc images, to instead build their systems from source using buildstream, the same way GNOME OS works. The idea is that this is no longer a "distribution" and doesn't have "packages" anymore, since the entire system is built from source into an image that can be updated to atomically. While this model is simpler and way less jank than assembling your OS in a dockerfile, the model of separating packaging from distribution makes things harder for users for no benefit over the alternative.

To elaborate: Buildstream is a build system created by gnome developers that works as follows:

- Various element are defined in yaml files with their dependency and build steps

- Buildstream forms a tree of build elements to evaluate

- Each element is evaluated in a sandbox with access to only its dependencies and the output is placed in a content-addressed store for caching

If you have experience with nix, you may recognize that this is almost the same way nix works, with the difference that buildstream dependencies are mounted to regular directories (e.g. /usr) in the build sandbox instead of directly dealt with as /nix/store objects, and that buildstream is much harder to extend. A nix build results in artifacts that live in the nix store and are symlinked to other paths in the nix store, while a buildstream build results in artifacts that are compatible with a more traditional directory structure.

The idea of GNOME OS being "distroless" and not having packages is misleading, as it does have packages. Only, the packages exist exclusively during the build process. In order for a user to modify their system, they must add a rule to the buildstream definitions their system is built from and rebuild the entire thing from source to generate a new system image, which is unnecessarily burdensome. This is because the content-addressed artifact store (buildstream's cache) that exists when building has no relationship to the content-addressed artifact store on the deployed system (ostree or oci storage). This is pointless indirection with no clear benefit. By not separating building from distribution, nixos (a project using the nix dsl to build a linux system) achieves the same benefits of this model without any of the drawbacks. Users can modify how their system works, use caches, add their own packages, and share/integrate these modifications freely without building their entire os again from source every time.

To put this power in perspective, adding a nginx server to your system on nixos amounts to adding to your nix configuration:

services.nginx.enable = true;

and then rebuilding, switching to the new system generation.

Imagine how painful it would be to do this via a dockerfile (based off a different image) or buildstream definitions...

Finally, I'd like to clarify that nixos is not perfect. There are many areas of that need improvement (documentation, evaluation speed, evaluation caching, ifd, error messages, etc). However, I believe nixos is a fundamentally better and simpler model than the one being pushed by a lot of the linux desktop ecosystem at the moment. I believe a lot of the work on infrastructure like bootc and buildstream would be better focused on nix/nixos, or at least would benefit from learning from them.