# How to Pull Container Images with Apple's Container Runtime: A Complete Guide

> Learn to pull container images using Apple's container runtime with the container image pull command. This guide covers platform constraints, concurrency, and output formats effectively.

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

---

**To pull container images with Apple's container runtime, use the `container image pull` command followed by the image reference, optionally specifying platform constraints, concurrency limits, and output formatsfunctions.**

The **apple/container** repository provides a full OCI-compatible container runtime that handles image pulling through a coordinated multi-step workflow. When you need to pull container images with Apple's container runtime, the tool orchestrates platform resolution, registry authentication, manifest retrieval, and concurrent layer downloads through both command-line and programmatic interfaces.

## Understanding the Pull Workflow

The `container image pull` command implements a six-stage pipeline that transforms a remote image reference into a locally stored OCI layout. This workflow is orchestrated by the **Container API Service**, which handles high-level registry communication, while the **OCI image store** manages local persistence.

### Platform Resolution Logic

The runtime determines which platform variant (OS + architecture) to pull using a strict precedence hierarchy defined in `DefaultPlatform.resolve` within [`Sources/Services/ContainerAPIService/Client/DefaultPlatform.swift`](https://github.com/apple/container/blob/main/Sources/Services/ContainerAPIService/Client/DefaultPlatform.swift) (lines 63-73):

1. **The `--platform` flag** overrides all other selectors when explicitly provided
2. **Separate `--os` and `--arch` flags** are consulted if `--platform` is omitted
3. **Environment variable** `CONTAINER_DEFAULT_PLATFORM` serves as the third fallback
4. **Host native platform** is used as the final default when no explicit selectors exist

This resolution occurs before any network requests, ensuring the client only downloads layers compatible with the target execution environment.

### Registry Connection and Authentication

After platform resolution, the runtime establishes a registry connection using the scheme selector (`http`, `https`, or `auto`, defaulting to `auto`). The client negotiates TLS certificates, prepares authenticated HTTP headers, and validates the registry endpoint before requesting manifests.

### Manifest Retrieval and Layer Download

The client requests the image manifest matching the resolved platform, then proceeds to layer acquisition:

- **Concurrent downloads**: Default concurrency is set to 3 parallel downloads
- **Configurable limits**: Use `--max-concurrent-downloads` to tune network utilization
- **Progress reporting**: Streams download status via `--progress` options (`auto`, `none`, `ansi`, `plain`, or `color`)

Layers are written directly into the local OCI image store as they arrive, with the final image metadata (configuration, history, and platform information) assembled only after all blobs complete verification.

## Pull Command Options and Flags

The `container image pull` command supports several flags that control the pulling behavior:

- `--platform <os/arch>`: Specify exact platform variant (e.g., `linux/amd64`)
- `--os` and `--arch`: Separate flags for platform components
- `--max-concurrent-downloads <n>`: Set parallel download limits (default 3)
- `--progress <style>`: Control output formatting (`auto`, `none`, `ansi`, `plain`, `color`)
- `--quiet`: Suppress progress output, showing only the image name
- `--format <type>`: Render results as JSON, YAML, or TOML instead of tabular format

## Practical Examples

### Basic Image Pull

Pull the latest Alpine Linux image for your current host platform:

```bash
container image pull docker.io/library/alpine:latest

```

### Cross-Platform Image Pulling

Pull a specific architecture when running on Apple Silicon but need AMD64 images:

```bash
container image pull --platform linux/amd64 docker.io/library/busybox:latest

```

Alternatively, use separate flags:

```bash
container image pull --os linux --arch amd64 docker.io/library/busybox:latest

```

### Optimizing Download Performance

Increase concurrent connections for faster pulls on high-bandwidth networks:

```bash
container image pull \
    --max-concurrent-downloads 5 \
    --progress plain \
    docker.io/library/nginx:stable

```

### Programmatic Pull with Swift API

For automation and integration, use the `ContainerAPIClient` module to pull images programmatically:

```swift
import ContainerAPIClient
import ContainerizationOCI
import Logging

let logger = Logger(label: "example")
let client = ContainerAPIClient()

do {
    // Resolve platform using same precedence as CLI
    let platform = try DefaultPlatform.resolve(
        platform: nil,               // no --platform flag
        os: nil,                     // no --os flag
        arch: nil,                   // no --arch flag
        log: logger)

    // Configure pull request
    let request = ContainerAPIClient.PullRequest(
        reference: "docker.io/library/redis:7",
        platform: platform,
        scheme: .auto,               // same as CLI default
        maxConcurrentDownloads: 4,
        progress: .auto)

    // Execute pull
    try await client.pull(request: request)
    logger.info("Image pulled successfully")
} catch {
    logger.error("Pull failed: \(error)")
}

```

This Swift implementation mirrors the CLI flow: platform resolution via `DefaultPlatform.resolve`, followed by a `PullRequest` that passes all options to the underlying client.

## Summary

- **Platform resolution** follows strict precedence: `--platform` flag overrides `--os/--arch` flags, which override the `CONTAINER_DEFAULT_PLATFORM` environment variable, which falls back to the host native platform (implemented in [`Sources/Services/ContainerAPIService/Client/DefaultPlatform.swift`](https://github.com/apple/container/blob/main/Sources/Services/ContainerAPIService/Client/DefaultPlatform.swift))
- **Concurrency control** defaults to 3 parallel downloads but can be tuned via `--max-concurrent-downloads` for network optimization
- **Output flexibility** ranges from interactive progress bars to machine-readable JSON through the `--format` flag
- **Programmatic access** is available through the `ContainerAPIClient` Swift module, exposing the same pull logic used by the CLI
- **Registry compatibility** supports standard OCI registries with automatic TLS negotiation and authentication handling

## Frequently Asked Questions

### How does platform resolution work when pulling images?

The runtime evaluates platform selectors in strict order: first checking the `--platform` flag, then separate `--os` and `--arch` flags, then the `CONTAINER_DEFAULT_PLATFORM` environment variable, and finally defaulting to the host's native platform. This logic resides in `DefaultPlatform.resolve` within the Container API Service.

### Can I pull images from private registries with authentication?

Yes, the runtime supports authenticated registry connections. The `ContainerAPIClient` negotiates TLS and prepares authenticated HTTP clients automatically when credentials are configured. The scheme can be forced to `https` for secure private registries or set to `auto` for protocol detection.

### How do I limit or increase download concurrency?

Use the `--max-concurrent-downloads` flag followed by an integer. The default value is 3 parallel downloads, but you can increase this for high-bandwidth connections or decrease it to reduce network impact on shared systems.

### What output formats are supported for pull results?

By default, the CLI displays a tabular summary of pulled layers. You can suppress output with `--quiet` (showing only the image name) or use `--format` to render results as JSON, YAML, or TOML for machine parsing. Progress indicators can be customized via `--progress` using styles like `ansi`, `plain`, or `color`.