# How apple/container Handles OCI Image Pulling and Content Store Management

> Discover how apple/container manages OCI image pulling and its content store, caching blobs by digest and unpacking for container execution.

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

---

**apple/container pulls OCI images by treating them as content-addressed descriptors stored in a deduplicated content store, orchestrating downloads through an XPC-based Images Service that caches blobs by digest and unpacks them into snapshots for container execution.**

The `apple/container` repository provides a Swift-native implementation of OCI-compliant container management. When performing OCI image pulling, the system decomposes images into manifests, configs, and layer blobs that persist in a content-addressable store. This architecture ensures efficient storage through automatic deduplication while enabling concurrent layer downloads and garbage collection of orphaned blobs.

## CLI Entry Point: ImagePull Command

The pull process begins in [`Sources/ContainerCommands/Image/ImagePull.swift`](https://github.com/apple/container/blob/main/Sources/ContainerCommands/Image/ImagePull.swift), where the `ImagePull` command parses user flags including `--arch`, `--os`, `--platform`, and `--max-concurrent-downloads`.

The command resolves the target platform using `DefaultPlatform.resolve` and normalizes the image reference via `ClientImage.normalizeReference`. It initializes a `ProgressBar` and `ProgressTaskCoordinator` to stream download and unpack progress to the terminal.

## Client-Side Pull Request

After parsing, the CLI forwards the request to `ClientImage.pull` within the `ContainerAPIClient` module. This method constructs a `ContainerAPIService` request that communicates with the XPC-based Images Service. The client acts as a thin wrapper, translating high-level pull requests into service calls while handling platform defaults and authentication contexts.

## Images Service Orchestration

The `ImagesService.pull` method in [`Sources/Services/ContainerImagesService/Server/ImagesService.swift`](https://github.com/apple/container/blob/main/Sources/Services/ContainerImagesService/Server/ImagesService.swift) serves as the central orchestrator. The service authenticates to the remote registry using environment variables or keychain credentials, then delegates to `imageStore.pull`.

The `maxConcurrentDownloads` parameter controls parallel layer fetches, defaulting to 3 concurrent downloads. This setting prevents network congestion while maximizing throughput for multi-layer images.

## Content Store Architecture and Deduplication

The `ImageStore` (provided by the `Containerization` Swift package) interacts with the **ContentStore** to manage blob persistence. The content store implements a content-addressed storage model with the following characteristics:

- **Digest-based storage**: Files are stored under the root directory using the blob's cryptographic digest as the key
- **Deduplication**: Identical layer digests are stored once and shared across multiple images, reducing disk usage
- **Existence checks**: The `contentStore.get(digest:)` method retrieves cached blobs if they already exist locally
- **Size tracking**: Helper methods report `totalAllocatedSize` and `contentDiskSize` for capacity management

When pulling an image, the store downloads the manifest, resolves layer digests, and fetches each blob from the registry only if not already present in the local store.

## Unpacking to Snapshot Store

After all blobs are present in the content store, `ImagesService.pull` returns an `ImageDescription`. The CLI then invokes `image.unpack(platform:progressUpdate:)` to extract the filesystem layers.

The **SnapshotStore** (also part of the `Containerization` package) manages this extraction, creating read-only filesystem snapshots in a dedicated directory. These snapshots serve as the root filesystem for container execution.

## Garbage Collection and Maintenance

The `ImagesService` provides `cleanUpOrphanedBlobs()` to remove blobs no longer referenced by any image manifest. This garbage collection mechanism prevents unbounded disk growth while preserving shared layers used by multiple images.

## Code Examples

Pull an image from the command line with platform constraints and a progress bar:

```bash
container image pull --arch amd64 --os linux alpine:latest

```

Programmatically pull an image using the Swift API:

```swift
import ContainerAPIClient
import ContainerPlugin

let config = try await Application.loadContainerSystemConfig()
let progress: ProgressUpdateHandler = { update in
    print("downloaded \(update.completed) / \(update.total) bytes")
}

let desc = try await ClientImage.pull(
    reference: "docker.io/library/alpine:latest",
    platform: nil,
    scheme: .auto,
    containerSystemConfig: config,
    progressUpdate: progress,
    maxConcurrentDownloads: 4
)

print("Pulled image digest: \(desc.digest)")

```

## Summary

- **Content-addressed storage**: The `ContentStore` uses blob digests as keys, ensuring identical layers are stored only once across all images
- **XPC service architecture**: `ImagesService` acts as the centralized authority for pull operations, authenticating to registries and managing the `ImageStore`
- **Concurrent downloads**: Layer fetches respect the `maxConcurrentDownloads` limit (default 3) to balance speed and resource usage
- **Automatic cleanup**: `cleanUpOrphanedBlobs()` removes unreferenced blobs to reclaim disk space
- **Snapshot isolation**: The `SnapshotStore` unpacks layers into read-only filesystems ready for container execution

## Frequently Asked Questions

### How does apple/container deduplicate image layers?

The `ContentStore` implements content-addressed storage where each blob is keyed by its cryptographic digest. When pulling an image, the system checks `contentStore.get(digest:)` before downloading. If the digest exists, the store reuses the existing blob, ensuring identical layers across different images consume disk space only once.

### What controls the number of concurrent downloads during an OCI pull?

The `maxConcurrentDownloads` parameter controls parallel layer fetches, with a default value of 3. This setting is available as a CLI flag (`--max-concurrent-downloads`) and as a parameter in `ClientImage.pull`, allowing users to tune network concurrency based on available bandwidth and system resources.

### How does the content store handle garbage collection?

The `ImagesService` provides `cleanUpOrphanedBlobs()` which traverses the content store and removes blobs not referenced by any active image manifest. This process runs automatically during maintenance operations, preserving shared layers that remain referenced while reclaiming space from deleted images.

### Can you programmatically pull images without using the CLI?

Yes. The `ContainerAPIClient` module exposes `ClientImage.pull`, which accepts an image reference, platform constraints, and a progress handler. This method communicates with the `ImagesService` via XPC, enabling Swift applications and tools to pull images directly without shelling out to the `container` command.