# How the BuildKit Builder Operates in apple/container and Configures Build Resources

> Discover how the BuildKit builder in apple/container operates. Learn how it configures build resources using ContainerSystemConfig and CLI flags for efficient container building.

- Repository: [Apple/container](https://github.com/apple/container)
- Tags: internals
- Published: 2026-07-02

---

**The BuildKit builder in apple/container is an isolated OCI container managed by the `container` CLI, which loads default resources from `ContainerSystemConfig`, overrides them via CLI flags parsed in [`Parser.swift`](https://github.com/apple/container/blob/main/Parser.swift), and orchestrates the builder lifecycle through [`BuilderStart.swift`](https://github.com/apple/container/blob/main/BuilderStart.swift) by fetching images, configuring resources, and booting the BuildKit daemon.**

The `apple/container` project provides a dedicated BuildKit builder that isolates image builds within a specialized container environment. When you execute `container builder` commands, the Swift implementation in [`BuilderStart.swift`](https://github.com/apple/container/blob/main/BuilderStart.swift) coordinates resource allocation, container lifecycle management, and daemon initialization. Understanding how the BuildKit builder operates and configures build resources requires examining the command implementation alongside the resource parsing logic in [`Parser.swift`](https://github.com/apple/container/blob/main/Parser.swift).

## Loading Global System Configuration

In [`Sources/ContainerCommands/Builder/BuilderStart.swift`](https://github.com/apple/container/blob/main/Sources/ContainerCommands/Builder/BuilderStart.swift), the `BuilderStart.start` method initiates the builder lifecycle by reading the global system configuration. The code calls `Application.loadContainerSystemConfig()` to obtain the default BuildKit container image, default CPU count, and default memory size for the builder instance.

This configuration serves as the fallback for all resource limits when explicit values are not provided via command-line flags. The default values are accessed around lines 58-62 in [`BuilderStart.swift`](https://github.com/apple/container/blob/main/BuilderStart.swift), establishing the baseline hardware constraints for the BuildKit environment.

## Parsing Build Resources from CLI Flags

Resource allocation is determined by the `Parser.resources` function located in [`Sources/Services/ContainerAPIService/Client/Parser.swift`](https://github.com/apple/container/blob/main/Sources/Services/ContainerAPIService/Client/Parser.swift). This helper processes the user-supplied `--cpus` and `--memory` flags, merging explicit values with the defaults loaded from `ContainerSystemConfig`.

The implementation handles the following logic:

- If a flag is omitted, the system default (`containerSystemConfig.build.cpus` or `containerSystemConfig.build.memory`) is applied
- The function constructs a `ContainerConfiguration.Resources` struct where `cpus` is an **Int** and `memoryInBytes` is calculated from the MiB value provided
- Parsing occurs at lines 5-23 in [`Parser.swift`](https://github.com/apple/container/blob/main/Parser.swift)

## Managing the Builder Container Lifecycle

The builder container is identified by the hardcoded name "`buildkit`". The `BuilderStart.start` method queries the container state using `client.get(id: "buildkit")` and implements intelligent reuse logic defined around lines 49-84:

- **Running with mismatched configuration**: If the container is active but differs in image, CPU, memory, environment, or DNS settings, the code stops and deletes the existing container before creating a fresh one
- **Stopped with matching configuration**: If the container exists in a stopped state and matches the desired configuration, the system simply restarts it via `startBuildKit`
- **Non-existent**: A new container is created from scratch

This ensures that resource changes are immediately applied without manual cleanup of stale containers.

## Fetching and Configuring the BuildKit Image

When creating a new builder instance, the system performs a multi-stage initialization sequence (lines 94-119 in [`BuilderStart.swift`](https://github.com/apple/container/blob/main/BuilderStart.swift)):

1. **Fetch**: The BuildKit image is retrieved from the registry using `ClientImage.fetch` with the platform `arm64/linux`
2. **Unpack**: The image is prepared via `image.getCreateSnapshot` before container creation
3. **Progress**: Real-time updates are emitted through `ProgressUpdateHandler` to display "Fetching BuildKit image" and "Unpacking BuildKit image" status messages

Following image preparation, a `ContainerConfiguration` is assembled (lines 124-148) with the following specifications:

- **Resources**: The `Resources` struct from the parsing stage (`config.resources = resources`)
- **Mounts**: Tmpfs mount at `/run` and the virtiofs export directory
- **Labels**: Identification markers `plugin:builder` and `role:builder`
- **Capabilities**: Granted `ALL` capabilities with optional Rosetta support
- **Networking**: Attachment to the default network with CLI-supplied DNS settings

## Launching the BuildKit Daemon

The `startBuildKit` helper function (defined at the end of [`BuilderStart.swift`](https://github.com/apple/container/blob/main/BuilderStart.swift), lines 306-340) completes the initialization by:

1. Booting the builder shim process inside the container using `client.bootstrap`
2. Starting the actual BuildKit daemon process
3. Implementing error handling that tears down the container via `client.stop` and `client.delete` if startup fails

This ensures the BuildKit daemon runs with the precise resource constraints and configuration assembled in previous steps.

## CLI Commands for Builder Management

The command-line interface documented in [`docs/command-reference.md`](https://github.com/apple/container/blob/main/docs/command-reference.md) (lines 702-754) exposes three primary builder sub-commands:

- **`container builder start`**: Accepts `-c`/`--cpus` and `-m`/`--memory` flags to override defaults, pulls the image, creates the container, and initializes BuildKit
- **`container builder status`**: Displays the current builder state and configuration in a human-readable table format
- **`container builder stop`** and **`container builder delete`**: Manage container lifecycle, with `delete` supporting `--force` to remove running instances

```bash

# Start the builder with 4 CPUs and 8 GiB of RAM

container builder start -c 4 -m 8G

# Show builder status (human-readable table)

container builder status

# Stop the builder (keeps the container image for later reuse)

container builder stop

# Force-delete the builder, discarding the container

container builder delete --force

```

For programmatic control from Swift tools:

```swift
import ContainerCommands

try await BuilderStart.start(
    cpus: 2,                     // optional – overrides config default
    memory: "4G",                // optional – overrides config default
    log: Logger(label: "example"),
    dnsNameservers: ["1.1.1.1"],
    dnsDomain: nil,
    dnsSearchDomains: [],
    dnsOptions: [],
    progressUpdate: { _ in },
    containerSystemConfig: try await Application.loadContainerSystemConfig()
)

```

## Summary

- The BuildKit builder operates as a standard OCI container named "`buildkit`" managed by the `container` client
- Default resources are defined in `ContainerSystemConfig` and loaded via `Application.loadContainerSystemConfig()` in [`BuilderStart.swift`](https://github.com/apple/container/blob/main/BuilderStart.swift)
- CLI flags `--cpus` and `--memory` are parsed by `Parser.resources` to create a `ContainerConfiguration.Resources` struct that overrides defaults
- The lifecycle manager intelligently reuses stopped containers with matching configurations or recreates them when resource limits change
- Image fetching uses `ClientImage.fetch` with `arm64/linux` platform targeting, followed by unpacking via `getCreateSnapshot`
- Container configuration includes resource limits, mounts, labels, capabilities, and DNS settings assembled in [`BuilderStart.swift`](https://github.com/apple/container/blob/main/BuilderStart.swift)
- The daemon is launched via `startBuildKit` using `client.bootstrap`, with automatic teardown on failure

## Frequently Asked Questions

### How do I specify custom CPU and memory limits for the BuildKit builder?

Pass the `-c` (or `--cpus`) and `-m` (or `--memory`) flags to the `container builder start` command. For example, `container builder start -c 4 -m 8G` allocates 4 CPU cores and 8 GiB of RAM. These values override the defaults stored in `ContainerSystemConfig.build.cpus` and `ContainerSystemConfig.build.memory`.

### What happens if I change the builder configuration while it's running?

If the existing "`buildkit`" container is running but its configuration differs from the requested resources (CPU, memory, image, environment, or DNS), the `BuilderStart.start` method automatically stops and deletes the existing container before creating a new one with the updated specifications. If the container is stopped but matches the desired configuration, it is simply restarted.

### Where are the default builder resource limits defined?

Default limits are stored in the global `ContainerSystemConfig` structure, accessed via `Application.loadContainerSystemConfig()` at the beginning of the `BuilderStart.start` function. The configuration specifies default values for `build.cpus` and `build.memory` that apply when CLI flags are omitted.

### How does the container tool determine which BuildKit image to use?

The tool uses the default BuildKit image specified in `ContainerSystemConfig`, fetched during the builder creation phase. The implementation in [`BuilderStart.swift`](https://github.com/apple/container/blob/main/BuilderStart.swift) calls `ClientImage.fetch` with the platform set to `arm64/linux` to pull the appropriate image from the registry before unpacking it with `image.getCreateSnapshot`.