# Common Patterns Used in apple/container: A Swift Architecture Deep Dive

> Explore common patterns in apple/container like protocol-oriented design Sendable constraints factory builder value-type configurations and Swift concurrency for a robust modular thread safe system

- Repository: [Apple/container](https://github.com/apple/container)
- Tags: deep-dive
- Published: 2026-06-27

---

**The apple/container repository leverages protocol-oriented design with Sendable constraints, factory and builder patterns, value-type configurations, and Swift concurrency primitives to create a modular, thread-safe container build system.**

The `apple/container` project is Apple's open-source Swift implementation for building and managing containers. Understanding the common patterns used in this codebase reveals how the team achieves clean separation of concerns, type-safe concurrency, and extensible plugin architecture without compromising performance.

## Protocol-Oriented Design with Sendable

All public abstractions in `apple/container` are declared as protocols that inherit from `Sendable`, ensuring they are safe to use across Swift concurrency domains. This approach encourages composition over inheritance throughout the codebase.

The `SocketForwarder` protocol in [`Sources/SocketForwarder/SocketForwarder.swift`](https://github.com/apple/container/blob/main/Sources/SocketForwarder/SocketForwarder.swift) demonstrates this pattern:

```swift
public protocol SocketForwarder: Sendable {
    func run() throws -> EventLoopFuture<SocketForwarderResult>
}

```

Similarly, `PluginFactory` and various `*Service` and `*Handler` protocols adopt `Sendable` to guarantee thread safety at the compiler level.

## Factory Pattern for Plugin Discovery

The codebase employs concrete factories to encapsulate plugin discovery and hide filesystem details. Both `DefaultPluginFactory` and `AppBundlePluginFactory` in [`Sources/ContainerPlugin/PluginFactory.swift`](https://github.com/apple/container/blob/main/Sources/ContainerPlugin/PluginFactory.swift) provide a single entry point for creating immutable `Plugin` value types.

The implementation discovers configuration files and binaries:

```swift
public func create(installURL: URL) throws -> Plugin? {
    guard let configURL = Self.findConfigURL(in: installURL, logger: logger) else {
        return nil
    }
    // ...
    return Plugin(binaryURL: binaryURL, config: config, resourceURL: resourceURL)
}

```

This pattern decouples plugin instantiation from complex filesystem traversal logic. To load a plugin in your own code:

```swift
import Logging
import ContainerPlugin

let logger = Logger(label: "com.example.myapp")
let factory = DefaultPluginFactory(logger: logger)

let pluginsURL = URL(fileURLWithPath: "/Library/Containers/MyPlugins")
if let plugin = try factory.create(parentURL: pluginsURL, name: "my‑tool") {
    print("Loaded plugin: \(plugin.name)")
}

```

## Builder Pattern for Container Orchestration

The `Builder` struct in [`Sources/ContainerBuild/Builder.swift`](https://github.com/apple/container/blob/main/Sources/ContainerBuild/Builder.swift) orchestrates the complex lifecycle of gRPC clients, NIO event-loop groups, and background tasks. It hides the intricate setup of the BuildKit shim behind a simple `build(_:)` interface.

The constructor wires dependencies and launches a background task:

```swift
self.clientTask = Task {
    do {
        try await grpcClient.runConnections()
    } catch is CancellationError { 
        // Handle graceful shutdown
    }
}

```

Users interact with a clean API while the builder manages connection state and resource cleanup. A complete usage example:

```swift
import ContainerBuild
import Logging
import NIO

let logger = Logger(label: "com.example.builder")
let group = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount)

let socket = try FileHandle(forWritingAtPath: "/tmp/buildsock")!
let builder = try Builder(socket: socket, group: group, logger: logger)

let config = Builder.BuildConfig(
    buildID: "my‑build‑01",
    contentStore: ...,
    buildArgs: [],
    secrets: [:],
    contextDir: "/path/to/context",
    dockerfile: Data(),
    dockerignore: nil,
    labels: [],
    noCache: false,
    platforms: [.amd64],
    terminal: nil,
    tags: ["latest"],
    target: "",
    quiet: false,
    exports: [],
    cacheIn: [],
    cacheOut: [],
    pull: true,
    containerSystemConfig: ...
)

try await builder.build(config)

```

## Value-Type Configuration and Immutable State

Configuration data is encapsulated in immutable structs passed by value. `Builder.BuildConfig`, `ProgressBar.ProgressConfig`, and the `Plugin` struct in [`Sources/ContainerPlugin/Plugin.swift`](https://github.com/apple/container/blob/main/Sources/ContainerPlugin/Plugin.swift) store all settings as constants.

This eliminates shared mutable state and simplifies reasoning about data flow across concurrent contexts. When configuration changes are needed, new structs are created rather than modifying existing instances.

## Asynchronous Streams and Task Cancellation

Long-running I/O operations use Swift's `async/await` with NIO's futures. The `Builder.build` method creates an `AsyncStream<ClientStream>` to communicate with the gRPC server:

```swift
let reqStream = AsyncStream<ClientStream> { cont in
    continuation = cont
}
// ...
for await message in reqStream {
    try await writer.write(message)
}

```

Cancellation propagates through `Task.cancel()` and graceful gRPC client shutdown. The `ProgressBar` in [`Sources/TerminalProgress/ProgressBar.swift`](https://github.com/apple/container/blob/main/Sources/TerminalProgress/ProgressBar.swift) uses a `Mutex<State>` to coordinate rendering tasks safely across threads:

```swift
public func start(intervalSeconds: TimeInterval = 0.04) {
    state.withLock {
        if $0.renderTask != nil { return }
        $0.renderTask = Task(priority: .utility) {
            await start(intervalSeconds: intervalSeconds)
        }
    }
}

```

To display progress in your application:

```swift
import TerminalProgress

let cfg = ProgressConfig(
    initialDescription: "Processing",
    initialItemsName: "files",
    initialTotalTasks: 100,
    initialTotalItems: nil,
    initialTotalSize: nil,
    outputMode: .ansi,
    terminal: .standardOutput
)
let bar = ProgressBar(config: cfg)
bar.start()

for i in 1...100 {
    bar.set(description: "Step \(i)")
    try await Task.sleep(nanoseconds: 50_000_000)
}
bar.finish()

```

## Dependency Injection via Logger

Components receive a `Logging.Logger` instance at initialization time, maintaining loose coupling and testability. The `Builder`, `DefaultPluginFactory`, and other classes accept logger dependencies through their constructors rather than accessing global state.

This pattern allows for easy substitution of mock loggers during testing and ensures that each component carries its own structured logging context.

## Rich Error Handling with Domain Enums

Errors are expressed as enums conforming to `CustomStringConvertible` rather than stringly-typed errors. `Builder.Error` and `Plugin` helpers in [`Sources/ContainerPlugin/Plugin.swift`](https://github.com/apple/container/blob/main/Sources/ContainerPlugin/Plugin.swift) provide structured error cases with clear diagnostics, enabling precise error matching and debugging without parsing text.

## Extension-Based Organization

Utility methods are added via extensions to keep core types uncluttered. `ProgressBar` uses extensions for rendering logic, while `Plugin` extensions handle name and Mach-service helpers. This keeps related functionality colocated without bloating the primary type definitions.

To implement a custom forwarder:

```swift
import NIO
import SocketForwarder

final class MyForwarder: SocketForwarder {
    private let channel: Channel

    init(channel: Channel) { self.channel = channel }

    func run() throws -> EventLoopFuture<SocketForwarderResult> {
        // Forward data from `channel` to a remote address …
        // Return a future that completes when the forwarding ends.
    }
}

```

## Modular File Layout

The project separates functional areas into distinct modules under `Sources/`: `TerminalProgress`, `SocketForwarder`, `ContainerPlugin`, `ContainerBuild`, and `ContainerPersistence`. Each module enables independent compilation and clear navigation.

Key files include:
- [`Sources/ContainerPlugin/Plugin.swift`](https://github.com/apple/container/blob/main/Sources/ContainerPlugin/Plugin.swift) – Plugin value type
- [`Sources/ContainerPlugin/PluginFactory.swift`](https://github.com/apple/container/blob/main/Sources/ContainerPlugin/PluginFactory.swift) – Factory implementations
- [`Sources/ContainerBuild/Builder.swift`](https://github.com/apple/container/blob/main/Sources/ContainerBuild/Builder.swift) – Build orchestration
- [`Sources/TerminalProgress/ProgressBar.swift`](https://github.com/apple/container/blob/main/Sources/TerminalProgress/ProgressBar.swift) – Progress UI
- [`Sources/SocketForwarder/SocketForwarder.swift`](https://github.com/apple/container/blob/main/Sources/SocketForwarder/SocketForwarder.swift) – Forwarding protocol
- [`Sources/ContainerPersistence/ConfigurationLoader.swift`](https://github.com/apple/container/blob/main/Sources/ContainerPersistence/ConfigurationLoader.swift) – Configuration loading
- [`Sources/ContainerPersistence/EntityStore.swift`](https://github.com/apple/container/blob/main/Sources/ContainerPersistence/EntityStore.swift) – Storage abstraction

## Summary

- **Protocol-oriented design with Sendable** ensures thread-safe abstractions across concurrency domains according to the `apple/container` source code.
- **Factory pattern** encapsulates complex plugin discovery logic in [`Sources/ContainerPlugin/PluginFactory.swift`](https://github.com/apple/container/blob/main/Sources/ContainerPlugin/PluginFactory.swift) behind simple creation methods.
- **Builder pattern** hides gRPC and NIO setup complexity in [`Sources/ContainerBuild/Builder.swift`](https://github.com/apple/container/blob/main/Sources/ContainerBuild/Builder.swift) while managing resource lifecycle.
- **Value-type configurations** eliminate shared mutable state through immutable structs like `BuildConfig` and `Plugin`.
- **Swift concurrency primitives** including `AsyncStream`, `Task`, and `Mutex` coordinate I/O and UI updates safely.
- **Dependency injection** via constructor-injected loggers keeps components loosely coupled and testable.
- **Modular architecture** separates concerns into independent compilation units under `Sources/`.

## Frequently Asked Questions

### What makes the apple/container codebase thread-safe?

The codebase achieves thread safety through **protocol-oriented design** with `Sendable` constraints, ensuring all public abstractions are safe to use across concurrency domains. Additionally, `Mutex<State>` protects shared state in components like `ProgressBar`, while value-type configurations prevent shared mutable state by design.

### How does the Builder pattern simplify container builds in apple/container?

The `Builder` struct in [`Sources/ContainerBuild/Builder.swift`](https://github.com/apple/container/blob/main/Sources/ContainerBuild/Builder.swift) encapsulates the complex initialization of gRPC clients, NIO event-loop groups, and background tasks. It exposes a simple `build(_:)` method that accepts a `BuildConfig` value type, hiding the intricate BuildKit shim setup and connection management from users while properly handling cancellation.

### Why does apple/container use factories for plugin creation?

Factories like `DefaultPluginFactory` in [`Sources/ContainerPlugin/PluginFactory.swift`](https://github.com/apple/container/blob/main/Sources/ContainerPlugin/PluginFactory.swift) encapsulate the filesystem details of discovering plugin binaries and configuration files. This pattern provides a single entry point for plugin instantiation, decouples the plugin system from filesystem specifics, and enables different factory implementations such as `AppBundlePluginFactory` for various deployment scenarios.

### How does the project handle cancellation of long-running operations?

Long-running operations use Swift's structured concurrency with `Task` and `AsyncStream`. Cancellation propagates via `Task.cancel()`, and components like the `Builder` catch `CancellationError` to perform graceful shutdown of gRPC connections. The `ProgressBar` uses `Mutex` to safely check and update task state before spawning new rendering tasks.