Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/chainguard-dev/melange/llms.txt

Use this file to discover all available pages before exploring further.

One of melange’s headline features is that it builds for multiple CPU architectures out of the box. When you run melange build, it iterates over every supported architecture and produces a separate set of APK files for each one — all without requiring you to write cross-compilation logic in your pipelines. QEMU user-mode emulation handles running foreign-architecture binaries transparently.

Supported architectures

melange can target the following architectures:
ArchitectureDescription
x86_6464-bit x86 (Intel/AMD)
aarch6464-bit ARM (Apple Silicon, AWS Graviton, etc.)
armv732-bit ARMv7
arm/v632-bit ARMv6
ppc64le64-bit POWER, little-endian
s390xIBM Z (mainframe)
38632-bit x86

Default behaviour: build for all architectures

If package.target-architectures is empty (or omitted), melange builds for every architecture in the list above:
package:
  name: hello
  version: 2.12
  epoch: 0
  description: "the GNU hello world program"
  # target-architectures not set → build for all
Running the build produces an output directory organised by architecture:
packages/
├── x86_64/
│   ├── hello-2.12-r0.apk
│   └── APKINDEX.tar.gz
├── aarch64/
│   ├── hello-2.12-r0.apk
│   └── APKINDEX.tar.gz
├── armv7/
│   ├── hello-2.12-r0.apk
│   └── APKINDEX.tar.gz
└── ...

Targeting specific architectures

At the command line

Pass --arch with a comma-separated list to restrict a build to one or more architectures:
# Build only for x86_64
melange build melange.yaml --arch x86_64

# Build for x86_64 and aarch64
melange build melange.yaml --arch x86_64,aarch64

# Build for the current host architecture
melange build melange.yaml --arch $(uname -m)

In the YAML file

Set package.target-architectures to restrict the build configuration itself:
package:
  name: my-x86-only-tool
  version: 1.0.0
  epoch: 0
  target-architectures:
    - x86_64
    - aarch64
The --arch flag overrides target-architectures when both are specified. Use the YAML field when a package genuinely cannot be built for certain architectures (e.g., it contains architecture-specific assembly).

How QEMU emulation works

When melange builds for an architecture that differs from the host CPU, it relies on binfmt_misc kernel support to transparently execute foreign-architecture ELF binaries through QEMU user-mode emulation. From the pipeline’s perspective, nothing changes — ./configure && make works the same whether the build is native or emulated. melange does not require cross-compilation toolchains, sysroots, or CROSS_COMPILE environment variables.
To enable binfmt_misc handlers on a Linux host, install qemu-user-static and run the appropriate registration command. On Docker Desktop and many CI environments (including GitHub Actions with the setup-qemu-action), this is already configured.

Architecture substitutions in pipelines

Use the built-in substitution variables to write architecture-aware pipeline steps without hardcoding values:
VariableExample valueDescription
${{build.arch}}aarch64melange architecture name
${{build.goarch}}arm64Go’s GOARCH equivalent
Example: downloading an architecture-specific binary in a pipeline:
pipeline:
  - runs: |
      ARCH="${{build.arch}}"
      curl -Lo /usr/bin/mytool \
        "https://example.com/releases/mytool-${ARCH}"
      chmod +x /usr/bin/mytool

Choosing a runner

melange supports three runners for executing pipeline steps. The right choice depends on your host operating system and whether you need to build for foreign architectures.

bubblewrap

Linux only. Uses bwrap to create a lightweight container from the guest directory. Fastest option on Linux; no Docker daemon required. The default on Linux hosts.

docker

Linux and macOS. Runs pipeline steps inside a Docker container. Requires Docker Desktop or a Docker daemon. The default on macOS hosts and any non-Linux platform.

qemu

Full VM. Boots a QEMU virtual machine for each build. Required for strict isolation or when binfmt_misc is not available. Slower than bubblewrap but most portable.
Select a runner explicitly with --runner:
# Use Docker
melange build melange.yaml --runner docker

# Use bubblewrap (Linux only)
melange build melange.yaml --runner bubblewrap

# Use QEMU
melange build melange.yaml --runner qemu

When to use which runner

ScenarioRecommended runner
Linux CI/CD, maximum speedbubblewrap
macOS local developmentdocker or qemu
Strict sandbox isolationqemu
Docker already in usedocker
No Docker daemon availablebubblewrap (Linux) or qemu

Using the Docker container image for multi-arch builds

The official melange container image supports multi-architecture builds when run with Docker:
docker run --privileged --rm -v "${PWD}:/work" \
  cgr.dev/chainguard/melange build melange.yaml
The --privileged flag is required to allow binfmt_misc registration and bubblewrap to function inside the container. To build only for the current host architecture:
docker run --privileged --rm -v "${PWD}:/work" \
  cgr.dev/chainguard/melange build melange.yaml --arch $(uname -m)

QEMU runner and build cache

When using the QEMU runner, the build cache is mounted read-only by default (using 9p + overlay). To persist cache writes back to the host — which can significantly speed up repeated builds — enable virtiofs:
QEMU_USE_VIRTIOFS=1 melange build melange.yaml --runner qemu --cache-dir /path/to/cache
See the Build Cache guide for full details.

Build docs developers (and LLMs) love