How to Build OCI Images Using BuildKit with the container build Command

The container build command leverages a lightweight Linux VM running BuildKit to transform Dockerfiles into OCI-compliant images on Apple silicon, supporting parallel execution, cross-platform builds, and configurable resource limits through the ~/.config/container/config.toml configuration.

The container CLI is Apple's native tool for creating and running OCI-compatible containers on macOS. When you need to compile a Dockerfile into a runnable image, the container build command orchestrates a specialized builder VM that runs the BuildKit engine—the same high-performance build system used by Docker—to produce standards-compliant OCI images optimized for Apple silicon.

How container build Works

When you invoke container build, the CLI does not build images directly on macOS. Instead, it communicates with a dedicated builder container that packages BuildKit inside a lightweight Linux VM.

The Builder VM Architecture

According to docs/command-reference.md, the container build command parses your CLI flags, prepares the local build context, and forwards the request to the container-builder-shim image (default ghcr.io/apple/container-builder-shim/builder:<tag>). This shim launches a lightweight VM, mounts your build context, and executes the Dockerfile inside BuildKit. The VM runs as a background service managed by container builder start and persists across builds to enable layer caching.

BuildKit Integration

BuildKit provides the underlying execution engine that implements parallel step processing, intelligent cache sharing, and multi-architecture output. As documented in docs/tutorials/start-here.md, BuildKit runs inside the builder VM and handles all instruction processing, from RUN commands to COPY operations. The resulting image is automatically stored as a type oci image in the local container store.

Starting the Builder Environment

Before building images, you must start the builder VM with sufficient resources. By default, the builder allocates 2 CPUs and 2 GiB of memory, but large builds require more.

Start the builder with custom resource limits:

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

You can verify the builder status anytime:

container builder list

To stop the builder and free resources:

container builder stop

Building Your First OCI Image

With the builder running, create a standard Dockerfile in your project directory. The build context (the directory containing the Dockerfile and any files to copy) is specified as the final argument to container build.

Create a simple Dockerfile:

FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "app.py"]

Build the image with a tag:

container build --tag myorg/web-app:latest --file Dockerfile .

List the resulting OCI image:

container image list

Run a container to verify:

container run -it myorg/web-app:latest

Advanced container build Options

Multi-Architecture Builds

BuildKit supports cross-compilation through the --arch, --os, and --platform flags. As specified in docs/command-reference.md, you can produce images for multiple architectures in a single invocation by repeating the --arch flag.

Build for both Apple silicon and Intel architectures:

container build \
  --tag myorg/web-app:latest \
  --arch arm64 \
  --arch amd64 \
  --file Dockerfile \
  .

Export Formats and Outputs

By default, container build writes OCI images to the local store. However, you can export to other formats using the --output flag, which accepts BuildKit-style exporter syntax.

Export as a tarball:

container build \
  --tag myorg/web-app:latest \
  --output type=tar,dest=./myimage.tar \
  .

Other supported export types include local (for unpacking to a directory) and oci (the default).

Build Secrets and Caching

BuildKit supports build secrets and cache control. Pass sensitive data without baking it into layers using the --secret flag, or bust the cache with --no-cache.

Build a specific stage while passing an environment secret:

container build \
  --target production \
  --no-cache \
  --secret id=MY_API_KEY,env=API_KEY \
  -t myorg/web-app:prod .

Configuring the Builder Environment

Persistent builder settings live in ~/.config/container/config.toml under the [build] section. As documented in docs/container-system-config.md, this file controls the builder image version, resource defaults, and Rosetta translation settings.

Example configuration:

[build]
cpus = 8
memory = "16g"
rosetta = false
image = "ghcr.io/apple/container-builder-shim/builder:0.12.0"

After editing the configuration, restart the builder to apply changes:

container builder stop
container builder start

According to docs/how-to.md, you can also adjust resources per-invocation with the --cpus and --memory flags on container builder start, making the config file ideal for personal defaults while CLI flags handle one-off adjustments.

Summary

  • The container build command requires a running builder VM (container builder start) that hosts the BuildKit daemon inside a lightweight Linux VM.
  • Build configurations default to 2 CPU/2 GiB but can be customized via CLI flags or the [build] section in ~/.config/container/config.toml.
  • BuildKit enables parallel execution, intelligent caching, and multi-architecture builds using --arch flags for cross-platform compatibility.
  • Output formats are configurable via --output, supporting OCI (default), tar archives, and local directory exports.
  • The builder image version and Rosetta settings are controlled through the system configuration file, with changes requiring a builder restart to take effect.

Frequently Asked Questions

What is BuildKit and why does container use it?

BuildKit is an advanced build engine developed by Docker that provides parallel step execution, efficient caching, and multi-platform support. According to the apple/container source code, the container CLI uses BuildKit because it generates OCI-compliant images efficiently while supporting modern Dockerfile features like multi-stage builds and secrets management. The builder VM runs BuildKit as its core processing engine.

How do I build images for multiple architectures simultaneously?

Use repeated --arch flags to specify target architectures in a single build command. For example, container build --arch arm64 --arch amd64 --tag myapp:latest . produces a multi-architecture manifest containing both variants. As implemented in docs/command-reference.md, BuildKit handles the cross-compilation automatically, leveraging Rosetta on Apple silicon unless explicitly disabled in the configuration file.

Where is the builder VM configuration stored?

The configuration lives at ~/.config/container/config.toml on your macOS system. The [build] section within this file, as documented in docs/container-system-config.md, specifies default CPU counts, memory limits, the builder shim image tag, and Rosetta translation settings. Any changes to this file require restarting the builder with container builder stop followed by container builder start to take effect.

How do I export a built image to a tarball instead of the local store?

Use the --output flag with type=tar. The syntax is container build --output type=tar,dest=./filename.tar -t myimage:latest .. As noted in docs/command-reference.md, this bypasses the local OCI store and writes the image directly to the specified destination, which is useful for sharing images with systems that do not have the container CLI installed or for archiving specific build artifacts.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →