Skip to main content

Buildx and Multi-Architecture Builds

If you deploy to both Intel/AMD servers (amd64) and ARM servers or Apple Silicon laptops (arm64), you need images that work on both architectures. Docker Buildx lets you build a single image that contains variants for multiple platforms, so docker pull automatically gets the right one.

How Multi-Architecture Images Work

A multi-arch image is not one image -- it is a manifest list that points to architecture-specific images. When someone pulls the image, Docker automatically selects the correct variant for their platform:

flowchart TD
A["docker pull app:1.0.0"] --> B{"What platform?"}
B -->|"amd64 server"| C["linux/amd64 image"]
B -->|"arm64 server"| D["linux/arm64 image"]
B -->|"arm64 Mac"| E["linux/arm64 image"]

F["Manifest List: app:1.0.0"] --> C
F --> D

style F fill:#e3f2fd,stroke:#1565c0
style C fill:#e8f5e9,stroke:#2e7d32
style D fill:#fff3e0,stroke:#ef6c00

This is transparent to the user -- they pull the same tag regardless of their platform.

Setting Up Buildx

Buildx is included with Docker Engine on modern installations. You need to create a builder instance that supports multi-platform builds:

# Create a new builder with multi-platform support
docker buildx create --use --name multiarch

# Verify it is set up and see supported platforms
docker buildx inspect --bootstrap

You should see linux/amd64 and linux/arm64 in the list of supported platforms.

Check Your Current Builders

docker buildx ls

This shows all available builders and which one is currently active.

Building Multi-Architecture Images

Basic Command

docker buildx build \
--platform linux/amd64,linux/arm64 \
-t registry.example.com/app:1.0.0 \
--push .

This single command:

  1. Builds the image for both amd64 and arm64
  2. Creates a manifest list that references both variants
  3. Pushes everything to the registry
Why --push?

Multi-arch builds produce images for platforms that may not match your local machine. The --push flag sends them directly to a registry where any platform can pull them. If you want to keep them locally for testing, use --load (but this only works for a single platform at a time).

With Multiple Tags

Apply the same tagging discipline from the previous lesson:

docker buildx build \
--platform linux/amd64,linux/arm64 \
-t registry.example.com/app:1.0.0 \
-t registry.example.com/app:sha-abc1234 \
--push .

Emulation vs Native Builds

When building for a platform different from your host, Buildx uses one of two approaches:

ApproachHow It WorksSpeedAccuracy
QEMU EmulationTranslates CPU instructions on the flySlow (2-10x slower)Good, but occasional edge cases
Native buildersUses actual hardware for each platformFastPerfect

For most projects, QEMU emulation works fine. For large projects or production pipelines where build speed matters, you can set up native builders on actual arm64 machines.

Check if QEMU is Available

docker run --rm --privileged multiarch/qemu-user-static --reset -p yes

This registers QEMU binary handlers so Docker can emulate other architectures.

Dockerfile Tips for Multi-Architecture Builds

Most Dockerfiles work across architectures without changes. However, watch for these patterns that can cause issues:

PatternProblemFix
Hardcoded binary download URLsURL points to amd64 binary onlyUse platform-aware logic or multi-platform packages
Architecture-specific apt packagesPackage name differs by architectureUse architecture-agnostic package names
CGO_ENABLED=1 in Go buildsLinks to platform-specific C librariesUse CGO_ENABLED=0 for static builds when possible

Using Platform Build Arguments

Docker provides built-in build arguments for platform-aware Dockerfiles:

FROM --platform=$BUILDPLATFORM golang:1.23-alpine AS build
ARG TARGETPLATFORM
ARG TARGETOS
ARG TARGETARCH

WORKDIR /src
COPY . .
RUN GOOS=$TARGETOS GOARCH=$TARGETARCH go build -o app .

FROM alpine:3.20
COPY --from=build /src/app /usr/local/bin/app
ENTRYPOINT ["/usr/local/bin/app"]

The $BUILDPLATFORM and $TARGETPLATFORM variables let you compile on your native platform (fast) while targeting the output platform.

Verifying Multi-Architecture Images

After pushing, verify that the manifest list contains both architectures:

docker manifest inspect registry.example.com/app:1.0.0

You should see entries for both linux/amd64 and linux/arm64 in the output.

Test on Each Architecture

If you have access to both platforms:

# On an amd64 machine
docker pull registry.example.com/app:1.0.0
docker run --rm registry.example.com/app:1.0.0 --version

# On an arm64 machine
docker pull registry.example.com/app:1.0.0
docker run --rm registry.example.com/app:1.0.0 --version

Both should pull the correct architecture-specific image automatically.

CI Pipeline Example

A typical CI pipeline for multi-arch images:

flowchart LR
A["Push Code"] --> B["CI Runner"]
B --> C["Setup Buildx"]
C --> D["Build amd64 + arm64"]
D --> E["Push to Registry"]
E --> F["Verify Manifest"]

style A fill:#f0f4ff,stroke:#4a6fa5
style D fill:#fff3e0,stroke:#ef6c00
style F fill:#e8f5e9,stroke:#2e7d32
# CI script
docker buildx create --use --name ci-builder || true
docker buildx inspect --bootstrap

docker buildx build \
--platform linux/amd64,linux/arm64 \
-t registry.example.com/app:${VERSION} \
-t registry.example.com/app:sha-${GIT_SHA} \
--push .

# Verify the manifest
docker manifest inspect registry.example.com/app:${VERSION}

When Do You Need Multi-Arch?

ScenarioMulti-Arch Needed?
All servers are amd64, all devs use amd64No -- single arch is simpler
Some developers use Apple Silicon (M1/M2/M3)Yes -- avoids emulation overhead during development
Deploying to both cloud (amd64) and edge (arm64)Yes -- required
Open source project with unknown user platformsYes -- supports widest audience

If your entire fleet is one architecture and you do not plan to change, single-arch builds are fine. Add multi-arch when you need it.

Key Takeaways

  • Multi-arch images use a manifest list to serve the right image for each platform automatically.
  • Use docker buildx build --platform linux/amd64,linux/arm64 --push to build and push for both architectures.
  • Create a dedicated Buildx builder with docker buildx create --use before building.
  • QEMU emulation makes multi-arch builds possible on any machine, but native builders are faster.
  • Verify your manifest list after pushing to confirm both architectures are present.
  • Not every project needs multi-arch -- add it when your deployment targets or developer machines require it.

What's Next