# How Container Handles Multi-Platform Image Builds with Rosetta on Apple Silicon

> Learn how Container effortlessly handles multi-platform image builds on Apple Silicon using Rosetta. Build x86_64 binaries seamlessly on M1/M2 chips without manual setup.

- Repository: [Apple/container](https://github.com/apple/container)
- Tags: how-to-guide
- Published: 2026-06-21

---

**Container leverages a dedicated BuildKit builder VM running under Rosetta translation to execute x86-64 binaries on Apple Silicon, enabling seamless cross-platform OCI image builds without manual emulation configuration.**

The `apple/container` tool simplifies multi-platform image builds on Apple Silicon by integrating Rosetta translation directly into its build pipeline. When you invoke `container image build` with a `--platform` flag, the tool orchestrates a specialized builder container that targets architectures like `linux/amd64` while executing natively on ARM64 hardware. This architecture combines Rosetta's transparent binary translation with BuildKit's native cross-platform capabilities to produce multi-architecture manifests without requiring separate QEMU infrastructure.

## Platform Selection and Precedence Rules

### Parsing the `--platform` Flag

When you specify `--platform <os>/<arch>` (for example, `--platform linux/amd64`), the CLI stores this request in the `ContainerAPIService.DefaultPlatform` helper. According to the source code in [`Sources/Services/ContainerAPIService/Client/DefaultPlatform.swift`](https://github.com/apple/container/blob/main/Sources/Services/ContainerAPIService/Client/DefaultPlatform.swift), the precedence rules follow a strict hierarchy:

1. **`--platform` flag** overrides everything
2. **`CONTAINER_DEFAULT_PLATFORM`** environment variable serves as the fallback
3. **Host defaults** derived from the local system architecture provide the final default

This resolved value propagates to `ClientImage.fetch`, ensuring the builder retrieves the correct architecture-specific manifest from multi-arch base images before the build begins.

### Manifest Resolution

The `fetch` routine uses the resolved platform identifier to select the appropriate image manifest from registry manifest lists. This guarantees that when building for `amd64` on an Apple Silicon host, the builder pulls AMD64 variants of base images rather than ARM64 variants, maintaining architectural consistency throughout the build process.

## Builder Container Configuration and Rosetta Integration

### Rosetta vs. QEMU Decision Logic

The core logic for enabling Rosetta translation resides in [`Sources/ContainerCommands/Builder/BuilderStart.swift`](https://github.com/apple/container/blob/main/Sources/ContainerCommands/Builder/BuilderStart.swift) within the `BuilderStart.start` method. When configuring the builder container, the code evaluates the `containerSystemConfig.build.rosetta` boolean:

```swift
// BuilderStart.swift (line 96-100)
let useRosetta = containerSystemConfig.build.rosetta
let shimArguments = [
    "--debug",
    "--vsock",
    useRosetta ? nil : "--enable-qemu",
].compactMap { $0 }

// ...
config.rosetta = useRosetta

```

When **`useRosetta`** evaluates to `true`, the builder container runs with Rosetta translation enabled. The container runtime starts the builder VM on Apple Silicon hardware, and the Rosetta translation layer automatically converts any x86-64 binaries that BuildKit launches during the build process.

If Rosetta is disabled via `--no-rosetta` or configuration files, the shim receives the `--enable-qemu` argument instead, causing the container runtime to start the VM with QEMU-based emulation rather than Rosetta translation.

### Configuration Sources

The default Rosetta behavior is controlled by `BuildConfig.defaultRosetta` in [`Sources/ContainerPersistence/ContainerSystemConfig.swift`](https://github.com/apple/container/blob/main/Sources/ContainerPersistence/ContainerSystemConfig.swift) (line 81), where the default value is set to `true`. Users can explicitly disable this behavior through:

- The `--no-rosetta` CLI flag
- Setting `rosetta=false` in [`config.toml`](https://github.com/apple/container/blob/main/config.toml)

## Cross-Platform Build Delegation to BuildKit

### BuildKit Multi-Platform Support

Container delegates the actual multi-architecture build to BuildKit running inside the configured builder container. BuildKit accepts a list of target platforms propagated from the `--platform` flag and performs the following operations:

- Pulls the appropriate base images for each requested platform
- Executes build instructions using the available architecture binaries (translated via Rosetta when targeting x86-64 on Apple Silicon)
- Produces a **manifest list** containing architecture-specific layers for all requested platforms

Because the builder container runs under Rosetta, x86-64 BuildKit binaries can execute on Apple Silicon hosts without modification. This allows a single `container image build` command to emit images for both `arm64` and `amd64` (or any other supported platform) while the host handles the architecture translation transparently.

## Practical Examples

Build a multi-architecture image for AMD64 using Rosetta translation (default behavior):

```bash
container image build \
    --platform linux/amd64 \
    --tag myrepo/example:latest \
    ./path/to/Dockerfile

```

Force QEMU emulation instead of Rosetta for the same build:

```bash
container image build \
    --platform linux/amd64 \
    --no-rosetta \
    --tag myrepo/example:latest \
    ./path/to/Dockerfile

```

## Summary

- **Platform precedence** follows the order: `--platform` flag > `CONTAINER_DEFAULT_PLATFORM` environment variable > host system defaults, as implemented in [`DefaultPlatform.swift`](https://github.com/apple/container/blob/main/DefaultPlatform.swift).
- **Rosetta translation** is enabled by default via `BuildConfig.defaultRosetta` in [`ContainerSystemConfig.swift`](https://github.com/apple/container/blob/main/ContainerSystemConfig.swift), allowing x86-64 binaries to run natively on Apple Silicon through automatic translation.
- **Builder configuration** in `BuilderStart.start` switches between Rosetta and QEMU by conditionally passing `--enable-qemu` to the container shim when Rosetta is disabled.
- **BuildKit delegation** handles the actual multi-platform image construction, producing manifest lists that contain architecture-specific layers for each requested platform.

## Frequently Asked Questions

### How does Container choose between Rosetta and QEMU for x86-64 builds?

Container checks the `rosetta` configuration value (defaulting to `true` in [`ContainerSystemConfig.swift`](https://github.com/apple/container/blob/main/ContainerSystemConfig.swift)) when starting the builder container in `BuilderStart.start`. If enabled, the builder VM runs with Rosetta translation; if disabled via `--no-rosetta` or configuration, the system passes `--enable-qemu` to the container shim to use QEMU emulation instead.

### Can I build for multiple architectures simultaneously with Container?

Yes. BuildKit supports multi-platform builds natively, and Container propagates the `--platform` flag to BuildKit running inside the builder container. BuildKit will pull the appropriate base images for each architecture and produce a manifest list containing all requested variants, whether you specify `linux/amd64`, `linux/arm64`, or multiple platforms.

### What happens if I don't specify a `--platform` flag?

If you omit the `--platform` flag, Container falls back to the `CONTAINER_DEFAULT_PLATFORM` environment variable, and finally to the host's native architecture as determined by [`DefaultPlatform.swift`](https://github.com/apple/container/blob/main/DefaultPlatform.swift). This ensures builds target the local machine architecture by default while maintaining the ability to override for cross-platform development.

### Where is the Rosetta default setting stored in the codebase?

The default value of `true` for Rosetta support is defined in [`Sources/ContainerPersistence/ContainerSystemConfig.swift`](https://github.com/apple/container/blob/main/Sources/ContainerPersistence/ContainerSystemConfig.swift) at line 81 within the `BuildConfig` structure. This value is accessed via `containerSystemConfig.build.rosetta` when `BuilderStart.start` configures the builder container.