How to Save and Load Container Images as TAR Archives Using the Apple Container Tool

The container CLI provides image save and image load subcommands to export and import OCI images as tar archives, using XPC communication with the Container API service to stream data without external runtime dependencies.

The apple/container repository provides a native Apple ecosystem implementation for managing OCI-compliant container images. When you need to transfer images between environments or create offline backups, you can save and load container images as tar archives using the built-in command-line interface and Swift API.

Architecture of the Save and Load System

The export and import workflow operates through a distributed architecture involving command-line parsers, XPC clients, and a dedicated image service.

CLI Entry Points

The user-facing commands are implemented in Sources/ContainerCommands/Image/:

  • ImageSave.swift – Handles the container image save command, gathering image references, optional platform selectors, and output paths
  • ImageLoad.swift – Implements container image load, accepting tar file paths or stdin input with an optional --force flag for invalid archives

Both commands utilize ArgumentParser with @Option, @Flag, and @OptionGroup decorators to expose CLI parameters.

XPC Client Communication

The commands delegate to ClientImage.swift (Sources/Services/ContainerAPIService/Client/), which builds an XPC client via newXPCClient to communicate with the container-core-images service (ClientImage.serviceIdentifier). Requests are encoded as XPCMessage objects and dispatched through XPCClient.send.

Server-Side Archive Processing

The actual tar creation and extraction occurs in ImagesService.swift (Sources/Services/ContainerImagesService/Server/):

  • For save operations, the service iterates over requested references, resolves OCI descriptors, streams layer blobs into a temporary directory, then tars the directory
  • For load operations, the service receives the tar file, validates members (rejecting invalid ones unless --force is set), and unpacks images into the content store

Saving Container Images as TAR Archives

To export images to a portable archive format, use the image save command.

Saving to a File

Specify the output path with the --output flag:

container image save alpine:latest --output alpine.tar

If you omit --output, the archive streams to stdout, enabling compression or direct piping:

container image save alpine:latest | gzip > alpine.tar.gz

Platform-Specific Exports

The ImageSave command supports platform selection through DefaultPlatform.resolve (defined in DefaultPlatform.swift). Use --os, --arch, or --platform flags, or set the CONTAINER_DEFAULT_PLATFORM environment variable:

container image save alpine:latest --platform linux/amd64 --output alpine-amd64.tar

Loading Container Images from TAR Archives

Import previously saved archives using the image load command.

Loading from a File

Specify the input path with the --input flag:

container image load --input alpine.tar

Loading from Standard Input

When --input is omitted, the command reads from stdin:

cat alpine.tar | container image load

Handling Invalid Archives

Use the --force flag to load archives containing invalid members that would otherwise be rejected:

container image load --input corrupted.tar --force

After successful loading, the command prints loaded image references to stdout, making it easy to script subsequent operations.

Direct Piping Between Save and Load

You can pipe the output of save directly into load to transfer images without touching the filesystem:

container image save busybox:latest | container image load

This streams the tar archive through a temporary file in FileManager.default.temporaryDirectory while the ProgressBar (from ProgressBar.swift) provides visual feedback for both operations.

Programmatic API Usage

The Swift API exposed in ClientImage.swift allows programmatic access to save and load functionality.

Saving Images Programmatically

import ContainerAPIClient
import Foundation

let refs = ["alpine:latest"]
let outPath = "/tmp/alpine.tar"

try await ClientImage.save(
    references: refs,
    out: outPath,
    platform: nil,               // Uses current platform
    containerSystemConfig: .default
)

Loading Images Programmatically

let result = try await ClientImage.load(
    from: outPath,
    force: false
)

for img in result.images {
    print("Loaded image:", img.reference)
}

The ImageLoadResult struct (defined in ImageLoadResult.swift) contains the list of loaded images and any rejected members.

Implementation Details

Progress Reporting

Both commands instantiate a ProgressBar (configured with ProgressConfig) to display task progress while streaming archives to and from the server.

Temporary File Handling

When reading from stdin (ImageLoad) or writing to stdout (ImageSave), the system creates temporary tar files in FileManager.default.temporaryDirectory. Data is processed in 4 KB chunks using FileHandle operations.

Error Handling

Errors are wrapped in ContainerizationError and surfaced via the CLI's log.error mechanism and Application.exit, providing consistent error reporting across the tool.

Summary

  • Use container image save to export OCI images as tar archives to files or stdout
  • Use container image load to import archives from files or stdin into the content store
  • Both commands support pipeline operations for efficient image transfer without intermediate files
  • The Swift API through ClientImage.save() and ClientImage.load() provides programmatic access for automation
  • Server-side processing in ImagesService.swift handles the actual archive creation and extraction, operating entirely within the Apple container subsystem without external runtimes

Frequently Asked Questions

Can I save multiple images to a single tar archive?

Yes. The ImageSave command accepts multiple image references as arguments and bundles them into a single archive. The server-side implementation in ImagesService.swift iterates over all references and includes their resolved OCI descriptors and layer blobs in the output tar.

How does the tool handle platform-specific images?

The DefaultPlatform.resolve method in DefaultPlatform.swift processes --os, --arch, and --platform arguments, falling back to the CONTAINER_DEFAULT_PLATFORM environment variable if set. This allows you to export images for specific architectures even when running on a different host platform.

What happens if a tar archive contains invalid members during load?

By default, the load operation validates archive members and rejects invalid ones. However, you can use the --force flag (handled in ImageLoad.swift) to override this behavior and force the loading of archives containing invalid members. The ImageLoadResult will indicate which members were rejected even when forcing the load.

Is external software required to create or extract the archives?

No. The container tool manages the entire OCI image lifecycle internally. The ImagesService.swift implementation handles tar creation and extraction directly without invoking external container runtimes or command-line tools like docker or tar.

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 →