# How melange and apko Work Together

> Source: https://www.ymotongpoo.com/books/chainguard-image-toolchain/35-melange-apko-integration/


The previous two hands-on chapters ran melange and apko separately. This chapter pulls together how the two relate, and summarizes what actually changes compared to a Dockerfile-based approach.

## Where the division of labor sits

The boundary between melange and apko is clean. melange's job is to fetch and build source code, then fix the result into the unit of an APK package. apko's job is solely to combine those APK packages into an OCI image. apko having no way to run commands is a direct response to the problem we saw in Chapter 2 — that freedom of instructions lowers verifiability. Making that constraint hold requires pushing every operation that needs a command, such as compiling, over to melange's side — and that's exactly why the two tools are separate.

This division keeps apko's YAML configuration remarkably easy to follow. Looking back at Chapter 7's `apko.yaml`, all it says is which packages to install, from which repositories, with what startup configuration. All of the build's complexity is concentrated on melange's `pipeline` side.

## The SBOM handoff from melange to apko

As we confirmed in Chapter 5, melange embedded an SPDX-format SBOM fragment inside the `hello` package at build time. When apko assembles an image, it detects this internal SBOM in each APK package being installed, and merges it into the image's overall SBOM.

This works because both tools assume the same SBOM data model, SPDX. If melange didn't generate an SBOM, apko would have to build its SBOM purely from package metadata (name, version, checksum), losing the detail of what was actually built inside that package. melange and apko can produce one consistent SBOM despite being separate tools precisely because they both honor this shared contract for the SBOM format.

## Reproducibility is secured in two stages

The weakness in a Dockerfile's reproducibility came from depending on the state of the repository at build time. With melange and apko together, reproducibility is secured in two stages.

First, at the melange stage, specifying a checksum like `expected-sha256` on the `pipeline`'s `fetch` action pins the content of the fetched source code. The build environment itself is also specified as APK package versions in `environment.contents`, so the build toolchain's composition follows the declaration too.

Then, at the apko stage, the combination of APK packages listed in `contents.packages` determines the layer contents. One thing worth noting here: `apko.yaml` itself declares package *names*, so the version resolved on any given build can still change if the repository index gets updated. This ambiguity has to be addressed either by pinning versions explicitly in `contents.packages`, or by rebuilding periodically in CI to keep drift within an acceptable range.

## Where this leaves us

The combination of melange and apko lets the whole path from source code to container image be explained in a shared vocabulary: declarative YAML, and an SBOM generated from inside the build. The next chapter looks at how these two tools come together in Chainguard's own production use.

