Apple Container Configuration File Structure: A Complete Guide to config.toml

Apple Container uses a layered TOML configuration file named config.toml that is searched in three locations—user home, app root, and install root—with settings merged in order of precedence and falling back to hard-coded defaults defined in ContainerSystemConfig.swift.

The open-source apple/container repository defines its runtime behavior through a hierarchical configuration system. The Apple Container configuration file follows the TOML format and supports layered overrides across user, application, and system directories, allowing developers to customize everything from builder VM resources to DNS domains and network subnets.

Configuration File Locations and Layered Precedence

Apple Container implements a first-match-wins precedence system that searches for config.toml in three distinct locations. The loader logic in Sources/ContainerPersistence/ConfigurationLoader.swift builds a layered snapshot from these paths, with earlier layers overriding later ones.

  • User-home (~/.config/container): The editable user configuration at config.toml takes highest priority.
  • App-root (…/config): A read-only copy at config/config.toml used by the application at runtime.
  • Install-root (/usr/local/etc/container): System-wide defaults shipped with the installation at etc/container/config.toml.

If a key is missing from every layer, the code defaults defined in Sources/ContainerPersistence/ContainerSystemConfig.swift are applied. If all files are absent, ConfigurationLoader.load() returns ContainerSystemConfig() containing the hard-coded defaults.

Top-Level Configuration Sections

The TOML schema is documented in docs/container-system-config.md. All top-level tables are optional; omitted sections fall back to the defaults defined in ContainerSystemConfig.swift.

[build] – Builder VM Resources

Controls the builder virtual machine settings for container builds.

  • rosetta: Bool (default: true) – Use Rosetta translation for non-native builds.
  • cpus: Int (default: 2) – CPU count for the builder VM.
  • memory: MemorySize (default: "2048mb") – RAM allocated to the builder VM.
  • image: String (default: ghcr.io/apple/container-builder-shim/builder:<tag>) – Builder image reference.

[container] – Per-Container Defaults

Defines default resource allocations for individual containers.

  • cpus: Int (default: 4) – Default CPU count for a container.
  • memory: MemorySize (default: "1g") – Default RAM for a container.

[dns] – DNS Domain Configuration

  • domain: String? (default: unset) – When set (e.g., "test"), hostnames acquire this suffix (e.g., my-web-server.test).

[kernel] – Guest Kernel Settings

  • binaryPath: String (default: "opt/kata/share/kata-containers/vmlinux-6.18.15-186") – Path inside the downloaded archive.
  • url: URL (default: https://github.com/kata-containers/kata-containers/releases/download/3.28.0/kata-static-3.28.0-arm64.tar.zst) – Archive URL used if the kernel is not present locally.

[network] – Subnet Defaults

  • subnet: CIDRv4? (default: unset) – IPv4 CIDR (e.g., "192.168.100.0/24").
  • subnetv6: CIDRv6? (default: unset) – IPv6 CIDR (e.g., "fd00:abcd::/64").

[registry] – Default Registry

  • domain: String (default: "docker.io") – Registry used when an image reference omits a host.

[vminit] – vminitd Image Configuration

  • image: String (default: ghcr.io/apple/containerization/vminit:<tag>) – Image for the vminitd daemon; the tag is derived from the bundled containerization version.

[plugin.] – Plugin-Scoped Configuration

Plugins may add their own tables under plugin.<id>. The plugin defines the schema; values are isolated per-plugin and scoped to the specific plugin ID.

Type Formats and Validation

The configuration system uses strongly-typed values beyond standard primitives.

MemorySize

Quoted strings with a numeric prefix and binary unit suffix (b, kb, mb, gb, tb, pb). Parsing is case-insensitive, and values are stored as binary amounts (powers of 1024). Example: "2048mb" or "4g". See Sources/ContainerPersistence/MemorySize.swift for the implementation details.

CIDRv4 and CIDRv6

Quoted strings containing standard CIDR notation. Examples: "192.168.100.0/24" for IPv4 or "fd00:abcd::/64" for IPv6.

How Configuration Loading Works

The loading process in ConfigurationLoader.swift follows a specific sequence to resolve the final configuration:

  1. ConfigurationLoader.configurationFile(_:) builds the concrete FilePath for the requested base (home, appRoot, or installRoot).
  2. load() creates a FileProvider<TOMLSnapshot> for each layer, allowing missing files to proceed without error.
  3. The snapshots are merged with earlier layers overriding later ones.
  4. ConfigSnapshotDecoder decodes the merged snapshot into ContainerSystemConfig, which supplies the defaults defined in its init() methods.

This layered approach ensures that user-specific settings in ~/.config/container/config.toml override application defaults while maintaining system-wide fallbacks.

Configuration File Examples

Minimal User Configuration

Create ~/.config/container/config.toml to override specific defaults:


# User-only overrides – everything else uses library defaults.

[build]
cpus = 4
memory = "4g"

[container]
memory = "2g"

[dns]
domain = "test"

[registry]
domain = "myregistry.example.com"

Plugin-Specific Configuration

Plugins can receive their own configuration tables:

[plugin.mylogger]
logLevel = "debug"
output = "/var/log/container.log"

The plugin mylogger defines its own schema; the core loader scopes the TOML snapshot to plugin.mylogger.

Programmatic Access in Swift

Access the loaded configuration at runtime:

import ContainerPersistence

// Load the layered configuration (user config overrides system defaults)
let systemConfig = try await ConfigurationLoader.load()

print("Builder CPUs:", systemConfig.build.cpus)          // → 4 (from example above)
print("Default DNS domain:", systemConfig.dns.domain ?? "none")

Summary

  • Apple Container configuration file uses TOML format named config.toml with layered loading from three locations.
  • Precedence order: User-home (~/.config/container) overrides App-root, which overrides Install-root (/usr/local/etc/container).
  • Top-level sections include [build], [container], [dns], [kernel], [network], [registry], [vminit], and [plugin.<id>].
  • Special types MemorySize, CIDRv4, and CIDRv6 provide validated parsing for resources and networking.
  • Implementation resides in ConfigurationLoader.swift for loading logic and ContainerSystemConfig.swift for defaults and data models.
  • Fallback behavior: If all configuration files are absent, hard-coded defaults from ContainerSystemConfig() are applied.

Frequently Asked Questions

Where does Apple Container look for the configuration file?

Apple Container searches three locations with first-match-wins precedence: the user home directory at ~/.config/container/config.toml, the application root at config/config.toml, and the installation root at /usr/local/etc/container/etc/container/config.toml. The search logic is implemented in Sources/ContainerPersistence/ConfigurationLoader.swift.

What format does the Apple Container configuration file use?

The configuration file uses TOML format. All top-level tables are optional, and the schema supports typed values including custom MemorySize strings (e.g., "2048mb") and CIDR notation for network subnets.

How are missing configuration keys handled?

If a key is missing from every configuration layer, the system falls back to hard-coded defaults defined in Sources/ContainerPersistence/ContainerSystemConfig.swift. If no configuration files exist at any layer, ConfigurationLoader.load() returns ContainerSystemConfig() initialized with these code defaults.

Can plugins define their own configuration sections?

Yes. Plugins can add custom tables under [plugin.<id>] where <id> is the plugin identifier. The plugin defines its own schema for values within that table, and the core configuration loader isolates these values per-plugin without enforcing a specific structure.

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 →