# rpm-ostree: atomic OS upgrades with package layering on top

> rpm-ostree mixes libostree's image-based upgrade model with RPM packages and libdnf's dependency handling, so an OS can be upgraded transactionally, rolled back without touching /etc or /var, and still carry locally installed packages. The project now says plainly that new bootable container work belongs in bootc and dnf5 instead.

**coreos/rpm-ostree** — ⚛📦 Hybrid image/package system with atomic upgrades and package layering

- Repository: https://github.com/coreos/rpm-ostree
- Website: https://coreos.github.io/rpm-ostree
- Stars: 1,033 · Forks: 220
- Language: C
- License: NOASSERTION
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/coreos-rpm-ostree

## Two systems, deliberately welded together

rpm-ostree calls itself a hybrid image/package system, and the description of how it works is more precise than the slogan.

The base image format is libostree, which is content-addressed and versioned. On top of that, rpm-ostree accepts RPM packages on both the client and the server side, and it shares code with the dnf project, specifically libdnf. The README names the pieces that come along with libdnf: the libsolv SAT solver for dependency resolution, librepo for RPM repository downloads, and librpm for the actual installation.

That combination is the whole point. A pure image system gives you atomicity but makes it awkward to ship a hotfix for one package. A pure package system gives you flexibility but no atomic upgrade and no rollback. rpm-ostree keeps the image as the unit of upgrade and the package as the unit of override, so the two models stop fighting each other.

The features list spells out the resulting behaviour. Upgrades are transactional and run in the background, and they are image-based, meaning versioned and checksummed artefacts rather than a mutation of the live filesystem, and both bootable container images and an ostree native HTTP model are supported as the source. Rollback is an OS-level operation that does not affect user data. Client-side package layering and overrides are supported. And custom base images can be produced either as a container with rpm-ostree compose image or as an ostree repository with rpm-ostree compose tree.

The primary language is C, the code is the base of several downstream products, and the documentation is published at coreos.github.io/rpm-ostree with the source in the repository's docs/ directory.

## Rollback that leaves /etc and /var alone

The rollback claim is the one to understand precisely, because "rollback" means different things in different systems.

rpm-ostree's rollback operates on the operating system tree, and it does not affect user data. The mechanism is libostree, and the split is expressed as /usr but not /etc and /var. The operating system content is the versioned, checksummed part, so it can be swapped to a previous deployment and swapped back. The configuration and the mutable state directories are not part of that swap, which means a rollback does not restore a machine to the state of last week, it restores the binaries to the state of last week while leaving the configuration as it is now.

That is a deliberate design choice and it cuts both ways. On the good side, a bad upgrade cannot leave a machine with new libraries and old configuration, and a rollback does not lose the settings someone changed in the meantime. On the other side, a rollback will not undo a configuration change that the previous OS version needed, which means a rollback can leave a machine in a state that never existed as a tested combination. Engineers who use this need to know that distinction.

The other half of the model is that upgrades are transactional and happen in the background. Because the deployment is prepared as a versioned artefact and only then switched to, a failed download or a failed boot leaves the running system alone. Combined with the checksummed nature of the images, this is what gives the system its reputation for not bricking machines during a bad release.

The package layering feature sits on this foundation. Because packages are applied as an overlay on top of a versioned base rather than mixed into it, the layering survives an OS upgrade and the base can move underneath it.

## Composing your own base image

If you are not using a stock image, rpm-ostree is the tool that produces one, and the choice is between two output formats.

The two commands are:

```bash
rpm-ostree compose image
rpm-ostree compose tree
```

compose image produces a container image, which is the format used by bootable container systems. compose tree produces an ostree repository, which is the classic ostree native layout served over HTTP.

The distinction matters because it decides how the machine fetches updates. A container image is pulled with a container runtime's tooling, and the transactional upgrade and rollback model comes from bootc and ostree as separate image systems. An ostree repository is served as a repository of versioned commits, and the client pulls the ones it needs.

Neither output is a package index. The image is a snapshot of a whole operating system, built from a package set at a point in time, and that snapshot is what gets versioned and checksummed. So the workflow for a product team is the familiar one of building a base image from a package manifest, publishing it, and letting clients upgrade transactionally, with the difference that the client keeps a previous version and can go back.

The build side of the project is set up for the same purpose. The Dockerfile at the repository root builds rpm-ostree from source and writes the updated binaries to a derived container image, with the base image selectable through a build argument, and the comment points at the Justfile for a working example. A default base of quay.io/fedora/fedora-bootc:44 is used, and the comment shows how to target CentOS with a centos-bootc base instead.

## Where the work is going: bootc and dnf5

The most useful thing in the README is a note about the future, and it deserves to be quoted rather than paraphrased. Development focus has shifted to bootc, to dnf, and to the ecosystem around those tools. rpm-ostree is widely in use today in many upstream projects and downstream products and continues to be supported. And in general, new major features related to bootable containers should land in those projects instead.

That is an unusually clear statement of a project's trajectory, and it changes how you should read the repository. rpm-ostree is not being abandoned, but it is not where bootable container work should go. The relationship in the project's own diagram is that rpm-ostree sits on top of ostree as an image system, on top of bootc as an image system, and on top of libdnf as the package system, with the daemon and CLI providing status, upgrade, rollback, package layering and the initramfs enable path.

For an engineer, the practical reading is straightforward. If you are operating an existing ostree or bootable container deployment, this is the tool that is still in use and still supported, and you should keep following it. If you are designing something new around bootable containers, the project is telling you that the new work belongs in bootc and in dnf5, and that rpm-ostree is the layer you consume rather than the one you extend.

The migration direction is visible in the dependencies. The project still builds against the classic dnf stack through libdnf, with the libsolv solver, librepo and librpm underneath, while the dnf link in the README now points at dnf5. That is a codebase in the middle of a generational change in the RPM tooling underneath it, which is worth keeping in mind when you plan a long-lived deployment on top of it.

## A C codebase with a Rust component and an autotools build

The repository is older and larger than the README suggests, and the directory listing tells you what you are dealing with.

The core is C, built with autotools, with configure.ac, autogen.sh and a set of Makefile fragments for the daemon, the library, the man pages, the tests and the shared library. There are separate source trees for the client library and for the private library, plus man/ for the manual pages, tests/ for the test suite, ci/ for the continuous integration scripts and experiments-and-demos/ for the less serious work.

The Rust component is the rpmostree-rust crate, a Cargo workspace with its own Cargo.toml and Cargo.lock. The crate metadata says the package is named rpmostree-rust at version 0.1.0, is not published to a registry, and uses edition 2021, with the Rust version deliberately held no newer than the current RHEL 8 rust toolset, and the comment explains that they are bumping to 1.48 so they can use cxx.rs. The link attribute names rpmostreeinternals, which is the mechanism the Rust side uses to call into the C internals, and the corresponding bridge files rpmostree-cxxrs.cxx and rpmostree-cxxrs.h sit at the repository root.

The system dependencies are declared twice, once in configure.ac and once in the Cargo manifest, with a comment that this duplication exists until Cargo becomes the single build system. The Rust side lists json-glib 1.0, libarchive 3.0, libcurl 7, polkit-gobject-1 and rpm 4.

There is also a Justfile, a Dockerfile, deny.toml for dependency policy, a .copr/ directory for the build service, api-doc/, RELEASE.md, HACKING.md and a .clang-format with a matching ignore file. The vendoring metadata in the Cargo file excludes test binaries and vendored source trees from the crate set, which is the sort of detail that only matters to someone producing a distribution tarball.

## Licences, releases and what to check

The licence situation is layered, and it is a real consideration if you are shipping a product built on this.

The README states that rpm-ostree includes code licensed under GPLv2+, LGPLv2+, and Apache 2.0 OR MIT, with the full text in the LICENSE file. The tree root shows the matching COPYING.GPL and COPYING.LGPL files. The repository's licence classification on GitHub is reported as a custom one that cannot be categorised, so the LICENSE file is the reference. For a project of this size the mixed licensing is normal, since it is assembled from many upstream components, but it does mean the terms of a derived distribution depend on which parts you ship.

The release cadence is a predictable quarterly pattern. v2026.1 was tagged on 2026-01-22, v2026.2 on 2026-06-08 and v2026.3 on 2026-09-10, with the last push on 2026-09-30. The version scheme is calendar based, which tells you the expectation is a release roughly every three months, 

The project is not archived, and the topics on the repository list centos, fedora, ostree and package-manager, which is a good description of where it is used.

Two things are worth checking before you commit to it in a new deployment. The first is the note about development focus, because it is the maintainers telling you where the future is. The second is the documentation itself: the README is a short index, and the real material is in docs/index.md and on the documentation website, including the details of the daemon protocol, the client and server deployment, the layering model and the compose workflows that the summary here only gestures at.

## Conclusion

Adopt rpm-ostree if you are running an ostree-based or bootable container operating system today and want transactional upgrades, a rollback that leaves user data alone, and the option to layer packages on top of a versioned image. Do not start new bootable container work here, because the project states that development focus has shifted to bootc and dnf5 and that new major features related to bootable containers should land in those projects instead. Before you deploy, read the documentation rather than the README, decide whether you want the ostree native HTTP model or container images, and check the licences you are actually shipping, since the tree mixes GPLv2+, LGPLv2+ and Apache 2.0 OR MIT code.

## FAQ

### What is rpm-ostree and how does it differ from plain dnf?

It is a hybrid image and package system. It uses libostree as the base image format, accepts RPM packages on both client and server, and shares code with dnf through libdnf, so upgrades are transactional and image-based while packages can still be layered on top.

### Does an rpm-ostree rollback affect my configuration and user data?

No. Rollback operates on the operating system tree through libostree, the /usr side, and leaves /etc and /var alone. A rollback therefore restores the binaries to a previous version while keeping your current configuration and data.

### What is the difference between rpm-ostree compose image and compose tree?

compose image produces a container image, the format used by bootable container systems, while compose tree produces an ostree repository in the native layout served over HTTP. The choice determines how clients fetch updates.

### Is rpm-ostree still being developed?

The repository is not archived and the last push was on 2026-09-30, with releases v2026.1, v2026.2 and v2026.3 through 2026. However, the README states that development focus has shifted to bootc, dnf and the ecosystem around them, that rpm-ostree continues to be supported, and that new major features related to bootable containers should land in those other projects.

### What licence does rpm-ostree use?

The README states that it includes code licensed under GPLv2+, LGPLv2+, and Apache 2.0 OR MIT, with the full text in the LICENSE file and the corresponding COPYING.GPL and COPYING.LGPL files in the tree.

## Sources

- [coreos/rpm-ostree on GitHub](https://github.com/coreos/rpm-ostree)
- [Issues](https://github.com/coreos/rpm-ostree/issues)
- [Project website](https://coreos.github.io/rpm-ostree)
- [README](https://github.com/coreos/rpm-ostree/blob/main/README.md)
- [Releases](https://github.com/coreos/rpm-ostree/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/coreos-rpm-ostree
