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:
- Builds the image for both amd64 and arm64
- Creates a manifest list that references both variants
- Pushes everything to the registry
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:
| Approach | How It Works | Speed | Accuracy |
|---|---|---|---|
| QEMU Emulation | Translates CPU instructions on the fly | Slow (2-10x slower) | Good, but occasional edge cases |
| Native builders | Uses actual hardware for each platform | Fast | Perfect |
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:
| Pattern | Problem | Fix |
|---|---|---|
| Hardcoded binary download URLs | URL points to amd64 binary only | Use platform-aware logic or multi-platform packages |
Architecture-specific apt packages | Package name differs by architecture | Use architecture-agnostic package names |
CGO_ENABLED=1 in Go builds | Links to platform-specific C libraries | Use CGO_ENABLED=0 for static builds when possible |
Using Platform Build Arguments
Docker provides built-in build arguments for platform-aware Dockerfiles:
FROM 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 /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?
| Scenario | Multi-Arch Needed? |
|---|---|
| All servers are amd64, all devs use amd64 | No -- 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 platforms | Yes -- 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 --pushto build and push for both architectures. - Create a dedicated Buildx builder with
docker buildx create --usebefore 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
- Return to the Images and Build Workflows module overview.
- Continue to Module 4: Containers and Runtime Management to learn how to run and manage containers.