How Image Caching Works in the Apple Container Tool: A Technical Deep Dive

The container command-line tool caches OCI images locally using a three-tier system comprising ImageStore for image manifests, ContentStore for addressable layer blobs, and BuildImageResolver for cache-to-registry resolution, enabling automatic reuse of downloaded layers across pulls and builds without redundant network traffic.

The container tool from the apple/container repository implements a sophisticated image caching mechanism designed to eliminate redundant network transfers and accelerate both image pulls and container builds. By storing OCI image manifests and layer blobs in local content-addressable stores, the tool can resolve dependencies from disk rather than fetching them repeatedly from remote registries. This architecture leverages three core components—ImageStore, ContentStore, and BuildImageResolver—to provide seamless caching across the pull, build, and run workflows.

Core Caching Components

The image caching architecture rests on three primary components that manage different aspects of the storage lifecycle:

How Pull Caching Works

When you execute container image pull <reference>, the tool follows a resolution path that prioritizes local cache before initiating network requests:

  1. ClientImage.pull is called (see Sources/ContainerAPIService/Client/ClientImage.swift at line 247).

  2. Inside ImagesService.pull, the ImageStore is consulted. If the requested image (identified by digest) already exists in the ImageStore, the call returns immediately without network traffic.

  3. If the image is not present, the service downloads the manifest and each missing layer, stores them in the ContentStore, and registers the image in the ImageStore for future reuse.


# Pull an image – will reuse cached layers if already present

container image pull alpine:latest

Build-Time Cache Management

The container build command supports explicit cache import and export through --cache-from and --cache-to flags. These populate the Builder.cacheIn and Builder.cacheOut arrays (see Sources/ContainerBuild/Builder.swift lines 282–284).

Cache-in workflow: When using --cache-from=mycache.tar, the resolver extracts layer tarballs from the supplied archive and populates the ContentStore. Subsequent build steps can reuse those layers without rebuilding them.

Cache-out workflow: After a successful build, --cache-to=mycache.tar writes any newly created layer tarballs into the archive, allowing reuse by later builds.

The resolver respects the pull boolean defined at line 284 in Builder.swift. When pull is false, only the local cache is consulted; when true, the resolver may still pull missing layers from a registry.


# Build with a cache-in archive (reuses previously built layers)

container build --cache-from=mycache.tar -t myapp .

# Build with a cache-out archive (exports newly built layers)

container build --cache-to=mycache.tar -t myapp .

Filesystem Caching for Running Containers

Beyond image layers, container supports host-side caching of mounted filesystems through the Filesystem.CacheMode enum defined in Sources/ContainerResource/Container/Filesystem.swift at lines 36–40. These modes are passed to the virtualization runtime (RuntimeService.swift lines 1357–1397) and affect I/O performance of block or volume mounts:

  • .on – Enable host caching (default).
  • .off – Disable host caching.
  • .auto – Let the system decide based on workload characteristics.

Summary

  • The image caching system in apple/container relies on three coordinated components: ImageStore for manifests, ContentStore for layer blobs, and BuildImageResolver for cache resolution logic.
  • During container image pull, the ImageStore is checked first at line 247 of ClientImage.swift, eliminating network calls when images exist locally.
  • Build pipelines can import and export caches explicitly using --cache-from and --cache-to, with logic managed in Builder.swift and BuildImageResolver.swift.
  • The pull flag in the builder determines whether cached layers are used exclusively or if network fallback is permitted.
  • Running containers benefit from configurable filesystem caching via CacheMode settings in Filesystem.swift.

Frequently Asked Questions

Where does the container tool store cached image layers?

The tool stores cached image layers in the ContentStore, a generic content-addressable cache defined in Sources/ContainerBuild/Builder.swift at lines 282–284. This store holds binary data including image layer blobs, while the ImageStore maintains the associated manifests and metadata.

How does the build process decide between using cached layers versus pulling from a registry?

The BuildImageResolver makes this determination based on the pull boolean flag. When pull is false, the resolver calls fetch() which queries the ContentStore first, only falling back to ClientImage.pull if the layer is missing. This logic is implemented in Sources/ContainerBuild/BuildImageResolver.swift at lines 82–85.

Can I export and import build caches between different machines?

Yes. The container build command supports --cache-to and --cache-from flags that allow you to export newly built layers to a tarball and import them on another system. The Builder class manages these through the cacheIn and cacheOut arrays, populating the ContentStore from archive files during subsequent builds.

Does filesystem caching affect running containers?

Yes. The Filesystem.CacheMode enum in Sources/ContainerResource/Container/Filesystem.swift (lines 36–40) controls host-side caching for mounted volumes, with options for .on, .off, and .auto. These settings are passed to the virtualization runtime in RuntimeService.swift and directly impact I/O performance for block or volume mounts.

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 →