For the complete documentation index, see llms.txt.

Adding a package to a Chainguard Container

Choose how to add a package to a Chainguard Container, find the package name, apply the change, and confirm the package reached the finished image.
  8 min read

Chainguard Containers ship with only the packages their application needs, so sooner or later you’ll want one that isn’t there. Custom Assembly is the supported way to add it. You declare the package you want, Chainguard builds the image on its own infrastructure, and Chainguard rebuilds that image whenever the package is updated. You can drive Custom Assembly from the Chainguard Console, interactively with chainctl, or non-interactively with chainctl from a pipeline.

This page helps you pick an approach, then covers the three steps that apply whichever one you pick: finding the package name, adding the package, and confirming that it reached the finished image.

Choose an approach

The following table compares the available approaches:

ApproachUse it whenWhat you need
Custom Assembly in the ConsoleYou want to browse the packages your organization can add and apply the change in a few clicks.A Console account with a role that has the repo.update capability.
Custom Assembly with chainctl, interactivelyYou work from a terminal and want to review a diff before it applies.chainctl, installed and authenticated.
Custom Assembly with chainctl, non-interactivelyYou keep image configuration in version control or apply it from CI/CD.chainctl and a YAML build configuration file.
Custom Assembly with the Chainguard APIYou’re building your own tooling around Custom Assembly.An API client and a Chainguard token.
apk add in a DockerfileYou build on a -dev variant or on wolfi-base, and you’re prepared to pin package versions and image digests yourself.A Dockerfile and a container image that includes apk.
apk with chroot in a multi-stage buildYou need a package in a distroless image and Custom Assembly doesn’t fit your workflow.A multi-stage Dockerfile.

Custom Assembly is the recommended approach because Chainguard’s build pipeline resolves the packages you add against the packages already in the base image, then rebuilds the image when any of them change. Adding packages with apk add in your own Dockerfile moves that work to you: without pinned package versions and image digests, a package update can conflict with an older dependency in the base image and break your build until a new base image is released. For the longer version of this argument, see Why use Custom Assembly for adding packages.

Note: Custom Assembly is available to organizations with access to production Chainguard Containers. If you use Chainguard’s free container images, take one of the Dockerfile approaches.

Before you begin

The Custom Assembly approaches on this page share these prerequisites:

  • Access to production Chainguard Containers.
  • A role with the repo.update capability, to customize an existing image in place, or the repo.create capability, to save the result as a new image. Of Chainguard’s three default roles — viewer, editor, and owner — only owner has both. For a custom role you can create instead, see Custom Assembly permissions requirements.
  • For the chainctl approaches, chainctl installed and authenticated.

Custom Assembly adds packages to an image; it can’t remove the packages the source image already contains. You can, however, remove packages you added in an earlier build.

Find the package name

You can add only the packages your organization is entitled to, which are the packages that appear in the Chainguard Containers you already have access to. Package names often carry a version stream — python-3.14 rather than python — so confirm the exact name before you add it. Look it up in the Console, or with apk from inside a running container.

Open the image in the Chainguard Console, click Customize image, then use the Filter packages box. The list holds every package your organization can add. If the package you want isn’t listed, open a Chainguard support ticket.

Add the package

The three procedures below all produce the same result. Pick the tab that matches how you work.

  1. In the Chainguard Console, open the image you want to customize.
  2. Click Customize image, then select the packages to add.
  3. Click Continue, then choose Create a new image or Customize current image.
  4. Click Preview changes and review the package list.
  5. Click Apply changes.

For the full walkthrough, including how to edit or remove customizations later, see Using the Chainguard Console to manage Custom Assembly resources.

Confirm the package is in the image

Custom Assembly builds run on Chainguard’s infrastructure and normally finish in under 20 minutes, so your change won’t reach the registry immediately.

  1. Check that the build succeeded:

    chainctl images repos build list --parent $ORGANIZATION --repo $CONTAINER
              START TIME           |        COMPLETION TIME        | RESULT  |             TAGS
    -------------------------------|-------------------------------|---------|-------------------------------
     Wed, 09 Sep 2026 12:46:56 CDT | Wed, 09 Sep 2026 12:47:13 CDT | Success | 26-full, 26.8-full, latest-full
     Wed, 09 Sep 2026 12:45:22 CDT | Wed, 09 Sep 2026 12:46:13 CDT | Success | 26-dev, 26.8-dev, latest-dev

    The Console shows the same information on the image’s Builds tab. Builds stay listed for 24 hours.

  2. Pull the image:

    docker pull cgr.dev/$ORGANIZATION/$CONTAINER:latest
  3. Check for the package. If the image includes apk, query it directly. apk info -e prints the package name when the package is installed and exits with a non-zero status when it isn’t:

    docker run --rm --entrypoint apk \
      cgr.dev/$ORGANIZATION/$CONTAINER:latest-dev info -e bash
    bash

    Distroless images have no apk, so read the image’s SBOM instead. This command lists the apk packages in the image:

    cosign download attestation \
      --platform linux/amd64 \
      --predicate-type https://spdx.dev/Document \
      cgr.dev/$ORGANIZATION/$CONTAINER:latest \
      | jq -r '.payload' | base64 -d \
      | jq -r '.predicate.packages[]
               | select(.externalRefs[]?.referenceLocator? // "" | startswith("pkg:apk/"))
               | .name'
    ca-certificates-bundle
    gdbm
    glibc-2.44
    ld-linux-2.44
    python-3.14

    The Console shows the same list on the image’s SBOM tab. For more ways to read this data, see Retrieving Chainguard Container SBOMs.

If the build fails

A Custom Assembly build reports failure only after it finishes. Retrieve the logs for a build with the logs subcommand, which prompts you to pick a build report:

chainctl images repos build logs --parent $ORGANIZATION --repo $CONTAINER

In the Console, click a row on the image’s Builds tab to open the same logs.

Builds fail for a few recurring reasons:

  • Two packages install the same file, and Custom Assembly can’t resolve the conflict.
  • A package is newer than the base image and was built against a newer version of glibc.
  • The build ran longer than an hour and timed out.
  • The package isn’t one your organization is entitled to.

For more on these cases, see Custom Assembly troubleshooting. If you can’t resolve a failure, contact Chainguard support.

Learn more

Last updated: 2026-09-10 12:23