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

> Explore how the apple container tool optimizes image caching with a three-tier system. Discover efficient layer reuse and reduced network traffic for faster builds and pulls.

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

---

**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:

- **`ImageStore`** – The on-disk store of images and layers that holds pulled image manifests and associated layer blobs. When `container image pull` is invoked, the store is queried first; if required layers are present, they are used directly, skipping network download. This is initialized in [[`Sources/Plugins/CoreImages/ImagesHelper.swift`](https://github.com/apple/container/blob/main/Sources/Plugins/CoreImages/ImagesHelper.swift)](https://github.com/apple/container/blob/main/Sources/Plugins/CoreImages/ImagesHelper.swift#L98) at line 98.

- **`ContentStore`** – The generic content-addressable cache providing backing for any binary data, including image layers. The build pipeline uses this to resolve layers from cache when needed for new images. The `Builder` class maintains references to this store in [[`Sources/ContainerBuild/Builder.swift`](https://github.com/apple/container/blob/main/Sources/ContainerBuild/Builder.swift)](https://github.com/apple/container/blob/main/Sources/ContainerBuild/Builder.swift#L282-L284) at lines 282–284.

- **`BuildImageResolver`** – The resolver that decides whether to pull from registry or fetch from cache. When a build step needs a base image, the resolver checks the `pull` flag. If `false`, it calls `fetch()` which first looks in the `ContentStore`; only if the image is missing does it fall back to `ClientImage.pull`. This logic is implemented in [[`Sources/ContainerBuild/BuildImageResolver.swift`](https://github.com/apple/container/blob/main/Sources/ContainerBuild/BuildImageResolver.swift)](https://github.com/apple/container/blob/main/Sources/ContainerBuild/BuildImageResolver.swift#L82-L85) at lines 82–85.

## 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`](https://github.com/apple/container/blob/main/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.

```bash

# 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`](https://github.com/apple/container/blob/main/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`](https://github.com/apple/container/blob/main/Builder.swift). When `pull` is **false**, only the local cache is consulted; when **true**, the resolver may still pull missing layers from a registry.

```bash

# 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`](https://github.com/apple/container/blob/main/Sources/ContainerResource/Container/Filesystem.swift) at lines 36–40. These modes are passed to the virtualization runtime ([`RuntimeService.swift`](https://github.com/apple/container/blob/main/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`](https://github.com/apple/container/blob/main/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`](https://github.com/apple/container/blob/main/Builder.swift) and [`BuildImageResolver.swift`](https://github.com/apple/container/blob/main/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`](https://github.com/apple/container/blob/main/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`](https://github.com/apple/container/blob/main/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`](https://github.com/apple/container/blob/main/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`](https://github.com/apple/container/blob/main/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`](https://github.com/apple/container/blob/main/RuntimeService.swift) and directly impact I/O performance for block or volume mounts.