# How to Build Container Images with the Apple Container CLI

> Learn to build OCI-compliant container images using Apple Container CLI and a Dockerfile. This guide details using the container build command with BuildKit for efficient image creation.

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

---

**Building container images with Apple's `container` tool requires a Dockerfile (or Containerfile), a running Linux builder VM that hosts BuildKit, and the `container build` command to compile layers into an OCI-compliant image stored in the local registry.**

The Apple `container` repository provides a Docker-compatible CLI for macOS that enables you to build container images using standard Dockerfiles while leveraging a lightweight Linux VM for build isolation. As documented in [`docs/tutorials/start-here.md`](https://github.com/apple/container/blob/main/docs/tutorials/start-here.md) and [`docs/command-reference.md`](https://github.com/apple/container/blob/main/docs/command-reference.md), this open-source tool implements the complete container image build workflow through BuildKit execution inside a configurable builder environment.

## Core Build Components

Three primary components work together to build container images:

- **Dockerfile**: A text file describing image layers, base images, `RUN` steps, and entrypoints. The CLI accepts both `Dockerfile` and `Containerfile` naming conventions.

- **Builder VM**: A lightweight Linux virtual machine defined in `ContainerSystemConfig.build` that isolates the build process from the host macOS system. Configuration includes CPU count, memory allocation, and the builder image reference (default: `ghcr.io/apple/container-builder-shim/builder:<tag>`), as specified in [`Sources/ContainerPersistence/ContainerSystemConfig.swift`](https://github.com/apple/container/blob/main/Sources/ContainerPersistence/ContainerSystemConfig.swift).

- **BuildKit**: The underlying build engine running inside the VM that executes Dockerfile instructions, handles layer caching, and produces OCI-compliant images.

## Step-by-Step Process to Build Container Images

### 1. Prepare Your Dockerfile

Create a `Dockerfile` in your project directory describing the desired image state. The repository provides reference examples in `examples/container-machine-vscode/Dockerfile`, demonstrating standard patterns such as base image selection, package installation, and command configuration.

### 2. Configure the Builder VM

The builder VM starts automatically on first build, but you can pre-configure resources using commands implemented in [`Sources/ContainerCommands/Builder/BuilderStart.swift`](https://github.com/apple/container/blob/main/Sources/ContainerCommands/Builder/BuilderStart.swift). This allows you to allocate sufficient CPU and memory for complex builds before compilation begins:

```bash
container builder start --cpus 8 --memory 32g

```

Resource limits and the builder image reference persist in [`Sources/ContainerPersistence/ContainerSystemConfig.swift`](https://github.com/apple/container/blob/main/Sources/ContainerPersistence/ContainerSystemConfig.swift) within the `ContainerSystemConfig.build` structure.

### 3. Execute the Build Command

Invoke the build process through the CLI implementation in [`Sources/ContainerCommands/BuildCommand.swift`](https://github.com/apple/container/blob/main/Sources/ContainerCommands/BuildCommand.swift). The command parses flags such as `--arch`, `--build-arg`, and `--memory`, then streams the build context to the builder VM:

```bash
container build --tag web-test --file Dockerfile .

```

The CLI communicates with the builder VM over vsock, transmitting the Dockerfile and build context for processing.

### 4. Monitor Build Progress

BuildKit streams layer creation progress to your terminal in real-time. You can suppress output with `-q/--quiet` for CI/CD environments, or export the image directly to a tarball using `--output type=tar,dest=./image.tar` without loading it into the local store.

### 5. Verify the Output

After the build completes, verify the image exists in the local OCI store managed by the `container-core-images` XPC helper:

```bash
container image list

```

You can now run the image locally, re-tag it for a registry, or push it to a remote repository using standard `container image` subcommands.

## Architectural Implementation

The build process follows this data flow according to the source implementation:

1. **CLI → Builder VM**: The `container` command parses user options, authenticates against `ContainerSystemConfig`, and establishes a vsock connection to the builder container.

2. **Builder VM → BuildKit**: Inside the VM, `container-builder-shim` (located at `/usr/local/bin/container-builder-shim`) launches BuildKit to process the Dockerfile steps and resolve build contexts.

3. **BuildKit → OCI Store**: Completed layers write to the local content store managed by `container-core-images`, an XPC helper launched by `ContainerAPIService` (see `Sources/Services/ContainerAPIService`). The resulting artifact is an OCI-compatible image that can be inspected with `container image inspect` or pushed to any OCI registry.

## Advanced Build Options

The `container build` command supports sophisticated workflows beyond basic image compilation:

- **Multi-architecture builds**: Compile for multiple platforms simultaneously: `container build --arch arm64 --arch amd64 -t myapp:latest .`

- **Build arguments**: Pass variables into the Dockerfile: `container build --build-arg NODE_VERSION=18 -t myapp .`

- **Cache control**: Disable layer caching for reproducible builds: `container build --no-cache -t myapp .`

- **OCI output**: Export to a specific destination without loading into the local store: `container build --output type=oci,dest=./myapp.tar -t myapp .`

## Summary

- Building container images requires a Dockerfile, a configured builder VM, and the `container build` command to orchestrate the process
- The builder VM configuration resides in [`Sources/ContainerPersistence/ContainerSystemConfig.swift`](https://github.com/apple/container/blob/main/Sources/ContainerPersistence/ContainerSystemConfig.swift), with defaults pointing to `ghcr.io/apple/container-builder-shim/builder`
- BuildKit executes inside the isolated VM while the CLI communicates via vsock, with implementation details in [`Sources/ContainerCommands/BuildCommand.swift`](https://github.com/apple/container/blob/main/Sources/ContainerCommands/BuildCommand.swift)
- Output produces OCI-compliant images stored locally through the XPC helper and manageable through standard CLI commands

## Frequently Asked Questions

### How do I increase memory for large container builds?

Use `container builder start --memory 32g` to allocate additional RAM to the builder VM before running `container build`. This configuration persists in `ContainerSystemConfig.build` and prevents out-of-memory errors during complex layer compilation involving large binaries or extensive package installations.

### Can I build container images for multiple architectures simultaneously?

Yes. Pass multiple `--arch` flags to the build command: `container build --arch arm64 --arch amd64 -t myimage:latest .`. BuildKit handles cross-compilation inside the builder VM, producing a multi-architecture manifest that can run on both Apple Silicon and Intel-based systems.

### Where does the builder VM image come from?

The default builder image is `ghcr.io/apple/container-builder-shim/builder:<tag>`, defined in [`Sources/ContainerPersistence/ContainerSystemConfig.swift`](https://github.com/apple/container/blob/main/Sources/ContainerPersistence/ContainerSystemConfig.swift). You can customize this reference through configuration options to use internal mirrors, air-gapped registries, or specific version tags required by your organization.

### How does the build process differ from Docker Desktop?

Unlike Docker Desktop's integrated daemon, Apple's `container` uses a separate builder VM managed through explicit `container builder` commands and communicates via vsock rather than a local Unix socket. While the BuildKit implementation remains compatible with standard Dockerfiles, VM resources require explicit management through `ContainerSystemConfig.build` settings rather than automatic allocation.