builds
Each entry in builds: defines one package build for one target distro. A project shipping to Debian 12 and Fedora 40 has two builds entries — typically deduplicated with YAML anchors so shared fields live in one place.
Keys per build entry
| Key | Required | Description |
|---|---|---|
distro |
yes | Distro ID — see Supported distros. Unknown IDs are silently skipped at build time |
package_name |
yes | Name of the resulting .rpm / .deb / .pkg.tar.zst |
maintainer |
yes | Name <email> — used in the spec/control Maintainer: field and changelog entries |
homepage |
yes | Project URL — written into the spec URL: and DEB Homepage: fields |
description |
yes | Short package description |
build_dependencies |
no | Distro package names installed in the container before the build. Names differ per distro family (qt6-base-dev on Debian, qt6-qtbase-devel on Fedora) — the main reason for per-family anchors |
runtime_dependencies |
no | Distro package names declared as runtime deps. Most projects need few or none; see below |
before_build_script |
no | Path (relative to source dir) to a shell script run inside the container before the package build, e.g. to install a toolchain that isn't in the distro repos |
rpm.spec_template |
RPM only | Path (relative to source dir) to a .spec.liquid file. Required for RPM-format distros |
deb.debian_templates |
DEB only | Path (relative to source dir) to a directory of debian/*.liquid files. Required for DEB-format distros |
pacman.pkgbuild_template |
pacman only | Path (relative to source dir) to a PKGBUILD.liquid file. Required for pacman-format distros (Arch, Manjaro) |
| (custom fields) | no | Arbitrary scalar values (string, bool, int, float — not arrays or objects) passed straight into the template context. See Templates |
Only the rpm:, deb:, or pacman: block matching the distro's package format is read, so each build entry needs the one for its format. They are usually defined once via a YAML anchor (see below) rather than repeated.
Unknown top-level keys in config.yml are silently ignored, which is what lets the anchor pattern below work cleanly.
When runtime_dependencies is needed
Rarely. rpmbuild and dpkg-shlibdeps scan the built binaries' linked libraries during the package build and add the providing distro packages as dependencies automatically, so the package already declares everything it dynamically links against.
Explicit entries matter for:
dlopen-loaded libraries — not present inDT_NEEDED, so the build-time scanner cannot see them. Anything loaded by name at runtime (plugins, optional codecs, GPU backends) must be listed.- Non-library runtime requirements — external tools the package shells out to (
gpg,ffmpeg,podman), data-only packages, fonts, themes. - Choice between alternatives — when more than one distro package can satisfy the same need (e.g. either
podmanordocker), declare the alternation explicitly. See syntax below.
runtime_dependencies syntax
Each entry is a plain distro package name like gpg or libqt5multimedia5-plugins — sufficient for most projects. Strings pass through verbatim into the rendered spec / control file, so use the syntax the target distro's package format understands.
OR-alternative forms — DEB pipe-OR (pkg | other-pkg) and RPM rich-dep syntax ((pkg or other-pkg)) — are only needed when more than one distro package can satisfy the same need. If a single distro package provides what you want, write its name as a plain string.
# Typical case: plain package names
runtime_dependencies: [gpg, ffmpeg]
# Alternation: only when either provider is acceptable
runtime_dependencies: ["podman | docker", gpg] # DEB target
runtime_dependencies: ["(podman or docker)", gpg] # RPM target
DRYing up with YAML anchors
Without anchors, shipping to ten distros means repeating the same package_name, maintainer, homepage, description, and template paths ten times. With anchors, each build entry shrinks to one or two lines.
A typical layout has three layers: common (shared across every build), per-format (RPM vs DEB plus template paths), and per-distro-family (where dependency lists diverge):
common: &common
package_name: my-app
maintainer: "You <you@example.com>"
homepage: https://example.com
description: A short description
rpm: &rpm
<<: *common
rpm:
spec_template: ".omnipackage/my-app.spec.liquid"
deb: &deb
<<: *common
deb:
debian_templates: ".omnipackage/deb"
pacman: &pacman
<<: *common
build_dependencies: [gcc, make, cmake]
pacman:
pkgbuild_template: ".omnipackage/PKGBUILD.liquid"
debian_family: &debian_family
build_dependencies: [build-essential, cmake]
<<: *deb
fedora_family: &fedora_family
build_dependencies: [gcc, make, cmake]
<<: *rpm
builds:
- distro: "debian_12"
<<: *debian_family
- distro: "debian_13"
<<: *debian_family
- distro: "ubuntu_24.04"
<<: *debian_family
- distro: "fedora_42"
<<: *fedora_family
- distro: "almalinux_9"
<<: *fedora_family
- distro: "arch"
<<: *pacman
- distro: "manjaro"
<<: *pacman
Syntax notes:
&namedefines an anchor;*namereferences it.<<:is YAML's merge key — it copies every key from the referenced mapping into the current one. Keys defined explicitly on the entry override merged values.- Anchors chain transitively:
*debian_familymerges*deb, which merges*common, so eachbuildsentry inherits everything up the chain. - The top-level keys
common:,rpm:,deb:,pacman:,debian_family:,fedora_family:are not OmniPackage config — they are YAML scratch space hosting anchors. The parser only readsversion_extractors:,builds:,repositories:,image_caches:,secrets:,ignore_source_files:. - Arch and Manjaro share one
*pacmananchor — same package format, same package names, both rolling — so no per-distro split is needed. - Per-distro entries can still override anything — a different
build_dependencieslist for one distro, abefore_build_scriptonly on older distros, and so on. Explicit keys win over merged ones.
For a multi-format project at scale (Qt5 vs. Qt6 splits, per-distro CMake flags), see mpz/.omnipackage/config.yml. For before_build_script on older distros only, see omnipackage-rs/.omnipackage/config.yml.
Custom fields
Any field on a build entry beyond the keys above lands in the template context under the same name. Use it for per-distro variation that doesn't fit build_dependencies or runtime_dependencies: CMake flags, environment exports, feature toggles. Values must be scalars (strings, bools, ints, floats); arrays and nested objects are not supported.
- distro: "ubuntu_20.04"
build_dependencies: [curl, make, gcc-10]
ENV_EXPORTS: "export CC=gcc-10"
before_build_script: ".omnipackage/install_rust.sh"
<<: *deb
{{ ENV_EXPORTS }} expands inside the spec or debian/rules template to set up the right toolchain before the build. Distros that don't set ENV_EXPORTS get an empty string, so the same template works everywhere without {% if %} guards.