Self-hosted service
estesp/manifest-tool avatar
estesp/manifest-tool

manifest-tool: inspecting and pushing multi-platform image indexes

Command line tool to create and query container image manifest list/indexes

840 stars102 forksGoApache-2.0

At a glance

What is it?
manifest-tool is a Go command line utility for viewing and pushing multi-platform container image references in an OCIv1 or Docker v2.2 compatible registry. It was one of the first tools able to assemble manifest lists, and it uses the containerd resolver, which brings both its ergonomics and its sharp edges.
Who is it for?
manifest-tool suits a release engineer who needs to check which platforms an image reference actually resolves to, or who needs to assemble and push an index by hand against a registry that supports the OCI distribution API.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What a manifest list actually is, and why a separate tool exists

manifest-tool is a command line utility used to view or push multi-platform container image references located in an OCIv1 or Docker v2.2 compatible container registry. The README is explicit about its place in the ecosystem: several other tools include more complete capabilities to view and manipulate the manifest objects associated with container images and artifacts, and manifest-tool was created as one of the first command line tools capable of assembling manifest lists, now more commonly known as indexes in the OCIv1 image specification.

That background explains the design. A manifest list, described in the Docker v2.2 distribution spec, or an index, described in the OCIv1 image spec, exists for one purpose: combining an array of architecture and platform specific container image manifests under a single reference.

The payoff is that a container runtime can select the appropriate index entry that matches the local node's architecture and platform. Before these kinds of manifests were available, setting up the right platform-specific image reference required separate instructions, configurations or code changes depending on the platform in use.

So the tool exists to make the multi-platform reference legible and movable. Inspect tells you what a reference contains. Push lets you construct an index and put it in a registry.

The audience is a release engineer or a platform engineer who deals in image references, particularly in a mixed-architecture setup where an amd64 image and an arm64 image need to live under one tag. The tool is written in Go and the source lives in a v2/ directory at the root, with the module path pointing at the v2 subpackage for the command.

Three ways to get it, including a Docker image for the CI box

Installation is offered in three forms, and the third one is aimed squarely at CI environments.

The releases are built with the latest Go version, and pre-built binaries for many architectures are published on the GitHub releases page.

The second form is a Docker image, automatically generated for a large number of architectures with each release, and used by simply running it.

sh
$ docker run mplatform/manifest-tool

Building from source needs a recent Go SDK and make.

sh
$ git clone https://github.com/estesp/manifest-tool
$ cd manifest-tool && make binary

And if you would rather not install a local development environment but do have Docker, the make build target compiles the tool inside the official Go SDK container.

There are two more Makefile targets worth knowing. The static target produces a statically linked binary, and the cross target builds a binary for all supported platforms using Go's cross-compilation support. For a release engineer shipping a tool across a fleet, the cross target is the one that matters.

The Makefile shows how the version is injected. The version comes from git describe --tags, cut to drop the leading character, and it is passed to the Go build as ldflags setting main.gitCommit and main.version. The commit value itself is annotated as dirty when the working tree has uncommitted changes, so a locally built binary tells you it is not a clean build.

The repository also carries a Dockerfile, and it is a development image rather than a runtime one. It starts from golang:1.26, installs the coverage and lint tools, clones the distribution project at a pinned commit to build a registry binary, and sets the working directory to the source path that the Makefile bind-mounts into it.

Inspect prints every manifest, its platform and its layer digests

The inspect command views the manifest of any image reference, given as a repo/image:tag combination. There is one constraint that trips people up and the documentation calls it out: you must provide a tag, even if the tag is latest, because the containerd resolver does not auto-append latest to image references, and manifest-tool uses the containerd resolver library.

The output is the interesting part. For a manifest list media type, it prints the reference name and type, the digest, and then the number of manifest references it contains.

sh
$ manifest-tool inspect golang:1.17
Name:   golang:1.17 (Type: application/vnd.docker.distribution.manifest.list.v2+json)
Digest: sha256:1a35cc2c5338409227c7293add327ebe42e1ee5465049f6c57c829588e3f8a39
 * Contains 10 manifest references:

Each entry gets a numbered block with its own type, digest and length, then its platform, then its layer digests.

sh
[1]     Type: application/vnd.docker.distribution.manifest.v2+json
[1]   Digest: sha256:a6c0b3e8b7d2faed2415448f20e75ed26eed6fdb1d261873ed4205907d92c674
[1]   Length: 1796
[1] Platform:
[1]    -      OS: linux
[1]    -    Arch: amd64
[1] # Layers: 7

The output distinguishes the platforms properly, including the Windows entries, which carry an OS version alongside the architecture.

sh
[10] Platform:
[10]    -      OS: windows
[10]    - OS Vers: 10.0.17763.2565
[10]    -    Arch: amd64

The README notes that the tool can inspect manifests of all media types within any registry supporting the OCI distribution API, which is a wider scope than the manifest list case, and it skips ahead when there are many entries so the output stays readable.

Pushing needs credentials and an index you assembled yourself

The second capability is pushing manifest list and index objects to a registry that supports the OCI distribution API and the appropriate Docker or OCI image specification.

The credential story is spelled out, and there are three options. You can provide registry credentials via the command line, use a credential helper application, which manifest-tool supports in the same way the Docker client does, or already be logged in to a registry and have an existing Docker client configuration file with credentials.

The third option is the one that matters operationally, because it means manifest-tool can reuse the credentials you already have, whether they came from a docker login or from a helper such as a cloud credential utility. That is the difference between a tool that fits into an existing pipeline and one that needs its own secret handling.

The model, then, is that the images already exist in the registry as individual architecture-specific manifests, and manifest-tool's job is to assemble the index that points at them and push that index under a tag. The alternative is to leave the whole thing to a build tool that understands multi-platform builds natively.

The README also notes a related project, mquery, for the read-only case. If you only need to query public image references to validate platform support, you can use mquery, which allows remote querying of public registry images.

sh
$ docker run --rm mplatform/mquery mplatform/mquery:latest
Image: mplatform/mquery:latest (digest: sha256:d0989420b6f0d2b929fd9355f15c767f62d0e9a72cdf999d1eb16e6073782c71)
 * Manifest List: Yes (Image type: application/vnd.docker.distribution.manifest.list.v2+json)
 * Supported platforms:
   - linux/ppc64le
   - linux/amd64
   - linux/386
   - linux/s390x
   - linux/riscv64
   - linux/arm64/v8

mquery itself is described as a small Go program running as an AWS Lambda function using a small cache so recent image results are cached, and the README links to a blog post from Moby Summit EU 2017 that describes the original creation of it.

The containerd resolver gives you exact behaviour and a strict tag rule

Two implementation choices shape how the tool behaves, and both come from the containerd resolver.

The first is the tag rule already mentioned. The resolver does not auto-append latest, so manifest-tool does not either. Every invocation needs an explicit tag. For a tool whose entire job is inspecting references, that is a defensible strictness: a reference without a tag is ambiguous, and the resolver will not guess.

The second is that the resolver is the thing doing the talking to the registry, which means the tool speaks the OCI distribution API rather than shelling out to a Docker daemon. That has a practical consequence. manifest-tool does not need a running Docker daemon, and it does not need the images present locally, which is what makes the Docker image route and the cross-compiled binary route sensible for a CI job that only needs to look at or push a reference.

The inspect output reinforces the same idea. The digests, lengths, media types and platform descriptors it prints are the raw registry objects, not a local daemon's interpretation of them, and it works for any registry that supports the OCI distribution API rather than only Docker Hub.

The Go module layout reflects the same structure. The command lives under v2/cmd/manifest-tool, the shared code under v2/pkg, and the Makefile's build target compiles from inside the v2 directory and writes the binary to the repository root. There is also a hack/ directory and an integration/ directory at the top level, alongside a .codespellrc, which suggests the project runs integration checks against a real registry.

Where manifest-tool is the wrong tool

The first wrong-tool case is a build pipeline that already assembles indexes for you. Modern build tooling can build and push a multi-platform image directly, and in that case manifest-tool is doing a job the builder already did. The tool earns its place when the platform-specific images exist and someone has to combine them, not when they were produced together in the first place.

The second case is a read-only check of a public image. The documentation points at mquery for exactly that need, and describes it as a smaller program built for remote querying of public registry images, running serverless with a cache. Using the full push-capable tool for a read is more installation than the job needs.

The third case is anything the OCI distribution API does not cover. The tool talks to registries that implement the OCI distribution API, and it assembles indexes per the Docker v2.2 or OCIv1 image specifications. A registry with a proprietary or older API, or a workflow that needs to manipulate the individual image manifests themselves rather than the index that points at them, is outside what this tool does. The README is upfront that other tools have more complete capabilities for viewing and manipulating manifest objects.

There is a release cadence point. The tags are v2.2.2 from 2026-05-06, v2.2.1 from 2025-09-24 and v2.2.0 from 2025-04-10, while the last push was on 2026-10-19. The tree is ahead of the newest tag, and the module path carries a v2 segment, so a consumer pinning v2.2.2 gets a slightly older binary than what is in the repository today.

On licensing, the project is Apache-2.0 with a LICENSE file at the root, which is a permissive grant with an explicit patent clause and no copyleft requirement on a tool you invoke from a script.

Editorial conclusion

manifest-tool suits a release engineer who needs to check which platforms an image reference actually resolves to, or who needs to assemble and push an index by hand against a registry that supports the OCI distribution API. It does not suit a workflow that only ever builds images with a buildx style tool, since pushing an index is the fiddly part it exists to solve, and it does not suit a read-only check of a public image, where the smaller mquery tool is the documented answer. Before adopting, run manifest-tool inspect against a reference you already trust, and note that the inspect command requires an explicit tag because the containerd resolver does not append latest for you.

Frequently asked questions

What does manifest-tool do?

It is a command line utility for viewing or pushing multi-platform container image references in an OCIv1 or Docker v2.2 compatible registry. It can inspect manifests of all media types, and push manifest list or index objects, and it uses the containerd resolver library to talk to the registry.

How do I install manifest-tool?

Pre-built binaries for many architectures are published with each release on the GitHub releases page, a multi-architecture Docker image is generated for each release and can be run with docker run mplatform/manifest-tool, or you can clone the repository and run make binary, which needs a recent Go SDK and make.

Why does manifest-tool require an explicit tag?

The tool utilizes the containerd resolver library, and that resolver does not auto-append latest to image references. So you must always supply a tag, even if the tag is latest itself.

How do I check which platforms a public image supports?

The documentation points to the related mquery project for remote querying of public registry images, which can be run as the mplatform/mquery Docker image. It prints whether the image is a manifest list and lists the supported platforms.

What credentials does manifest-tool need when pushing?

You can pass registry credentials on the command line, use a credential helper application in the same way the Docker client does, or already be logged in to a registry with an existing Docker client configuration file holding the credentials.

Official sources

  1. estesp/manifest-tool on GitHub
  2. Issues
  3. License: Apache-2.0
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/estesp-manifest-tool.svg)](https://hysenlabs.com/projects/estesp-manifest-tool)

Was this useful?