Docker from Basics to Production · Production-Ready Images

Multi-Platform Images (amd64 and arm64)

Why an image built on an Apple Silicon laptop fails on an x86 server, and how multi-platform builds fix it.

Create a free account to save this page, take notes and track your progress. Sign in

What you'll build

You'll inspect which platforms popular images support, see what platform a local image was built for, and learn the docker buildx build --platform workflow that publishes one tag for both amd64 and arm64.

The idea

Container images contain native binaries, so they are built for a platform (OS and CPU architecture). ARM servers (AWS Graviton, Azure Cobalt, Google Axion) and Apple Silicon laptops are common, so mismatches happen:

  • A single-platform image built on an arm64 laptop fails on an amd64 server with exec format error.
  • A multi-platform image is an index (manifest list) pointing to one image per platform; the runtime pulls the right one automatically.
docker buildx build --platform linux/amd64,linux/arm64 -t registry.example.com/api:1.4.2 --push .

Builds for a foreign architecture use QEMU emulation (slow) or native builders per platform; compiled languages can often cross-compile instead (GOARCH=arm64).

The code

Which platforms does each image support?
for img in python:3.14-slim nginx:1.29-alpine gcr.io/distroless/static-debian13; do
  platforms=$(docker buildx imagetools inspect "$img" --format '{{json .Manifest}}' |
    python3 -c 'import json,sys; m=json.load(sys.stdin); print(" ".join(sorted({p["platform"]["os"]+"/"+p["platform"]["architecture"] for p in m.get("manifests", []) if p.get("platform", {}).get("os") != "unknown"})))')
  echo "$img: $platforms"
done
echo "local alpine:3.24 was pulled for: $(docker image inspect alpine:3.24 --format '{{.Os}}/{{.Architecture}}')"

Output

python:3.14-slim: linux/386 linux/amd64 linux/arm linux/arm64 linux/ppc64le linux/riscv64 linux/s390x
nginx:1.29-alpine: linux/386 linux/amd64 linux/arm linux/arm64 linux/ppc64le linux/riscv64 linux/s390x
gcr.io/distroless/static-debian13: linux/amd64 linux/arm linux/arm64 linux/ppc64le linux/riscv64 linux/s390x
local alpine:3.24 was pulled for: linux/amd64

Run this on your computer — see “Get Started” for setup.

Common mistakes

  • Building on an arm64 laptop and pushing straight to an amd64 cluster.
  • Assuming every base image supports every architecture; check with imagetools inspect.
  • Emulating slow builds on QEMU when the language can cross-compile.
  • Native dependencies (C extensions) that have no wheel or binary for one of the platforms.

Key points

  • Images are per platform; a multi-platform tag is an index of per-platform images.
  • Build and push both amd64 and arm64 with docker buildx build --platform.
  • Prefer cross-compilation or native builders over emulation for speed.

Further reading: Multi-platform builds · docker buildx imagetools

Practice questions

What causes 'exec format error' when starting a container?

Answer

The image's binaries were built for a different CPU architecture than the host, for example an arm64 image on an amd64 server.

What is a multi-platform image?

Answer

An image index (manifest list) under one tag that points to separate images for each platform; clients pull the one matching their OS and architecture.

Why is cross-compilation often better than QEMU emulation for multi-platform builds?

Answer

Compiling natively for the target architecture (for example GOARCH=arm64) is much faster than running the whole build under emulation.

Open in the app to mark lessons complete, take notes and track your progress.

Was this page helpful?