# How to Configure System Properties Using config.toml in Apple Container

> Learn how to configure system properties in Apple Container using config.toml. Master merging user settings with system defaults for seamless daemon startup.

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

---

**Apple Container reads system properties from a layered set of [`config.toml`](https://github.com/apple/container/blob/main/config.toml) files, merging user settings in `~/.config/container/config.toml` with system defaults and applying them when the daemon starts.**

The Apple Container project provides a flexible configuration system that allows you to customize VM resources, DNS settings, registry endpoints, and plugin behavior through TOML files. Understanding how to configure system properties using [`config.toml`](https://github.com/apple/container/blob/main/config.toml) in Container enables you to tune the runtime environment without modifying source code. This guide explains the configuration schema, file precedence, and practical workflows based on the actual implementation in the `apple/container` repository.

## Configuration File Locations and Precedence

The `ConfigurationLoader` implemented in [`Sources/ContainerPersistence/ConfigurationLoader.swift`](https://github.com/apple/container/blob/main/Sources/ContainerPersistence/ConfigurationLoader.swift) searches for [`config.toml`](https://github.com/apple/container/blob/main/config.toml) in three distinct locations, applying a **first-match-wins** precedence order:

| Layer | Path | Role |
|-------|------|------|
| **User** | `~/.config/container/config.toml` | Editable by the logged-in user; highest priority. |
| **App-root** | `<app-root>/config/config.toml` | Read-only snapshot that the daemon uses at runtime. |
| **Install-root** | [`/usr/local/etc/container/config.toml`](https://github.com/apple/container/blob/main//usr/local/etc/container/config.toml) | System-wide defaults shipped with the installer. |

When `ConfigurationLoader.load()` executes, it builds a list of `FileProvider<TOMLSnapshot>` instances for each layer, merges them into a single `ConfigSnapshot`, and decodes the result into `ContainerSystemConfig`. Values defined in the user file shadow those in the app-root and install-root files.

## Configuration Schema and Structure

The TOML schema is defined by the `ContainerSystemConfig` class in [`Sources/ContainerPersistence/ContainerSystemConfig.swift`](https://github.com/apple/container/blob/main/Sources/ContainerPersistence/ContainerSystemConfig.swift). Each top-level table maps to a specific nested struct:

- `[build]` → `BuildConfig` (builder VM resources)
- `[container]` → `ContainerConfig` (default per-container resources)
- `[dns]` → `DNSConfig` (DNS domain settings)
- `[kernel]` → `KernelConfig` (kernel parameters)
- `[network]` → `NetworkConfig` (networking options)
- `[registry]` → `RegistryConfig` (default registry endpoint)
- `[vminit]` → `VminitConfig` (initialization settings)
- `[plugin.<id>]` → Plugin-specific configurations

All sections are optional; omitted keys fall back to the hard-coded defaults defined in the struct initializers. The file must be **UTF-8** encoded and use standard TOML table syntax as documented in [`docs/container-system-config.md`](https://github.com/apple/container/blob/main/docs/container-system-config.md).

## How to Edit and Apply Configuration

### Step 1: Create the User Configuration File

Create and edit the user-level configuration file using standard shell commands:

```bash
mkdir -p ~/.config/container
touch ~/.config/container/config.toml
$EDITOR ~/.config/container/config.toml

```

### Step 2: Define Your Properties

Add only the tables and keys you wish to override. For example, to disable Rosetta translation and adjust resource limits:

```toml
[build]
rosetta = false
cpus = 4
memory = "4096mb"

[container]
cpus = 2
memory = "2g"

[dns]
domain = "test"

[registry]
domain = "my-registry.example.com"

```

In this example, the `[build]` table overrides builder VM resources, `[container]` changes default per-container allocations, `[dns]` appends `.test` to hostnames, and `[registry]` sets the default registry for unqualified image names.

### Step 3: Apply the Configuration

When you run `container system start`, the daemon automatically copies your user configuration to the app-root location via `ConfigurationLoader.copyConfigurationToReadOnly`, making it read-only for runtime use. If the daemon is already running, restart it to reload the snapshot:

```bash
container system restart

```

## Loading Configuration Programmatically

For Swift applications interacting with the container system, access the merged configuration using the `ConfigurationLoader` class:

```swift
import ContainerPersistence
import SystemPackage

// Load the merged configuration (user + system defaults)
let systemConfig = try await ConfigurationLoader.load()

print("Builder image: \(systemConfig.build.image)")
print("Default container CPUs: \(systemConfig.container.cpus)")
print("DNS domain: \(systemConfig.dns.domain ?? "none")")

```

The `load()` method returns a fully populated `ContainerSystemConfig` instance with merged values from all three layers. You do not need to specify file paths; the loader resolves locations automatically.

## Plugin-Specific Configuration

Plugins can define custom configuration tables using the `[plugin.<id>]` syntax. For example, to configure a runtime plugin:

```toml
[plugin.runtime]
logLevel = "debug"
maxConcurrent = 4

```

Access plugin configuration in Swift by implementing the `LoadablePluginConfiguration` protocol:

```swift
struct RuntimePluginConfig: LoadablePluginConfiguration {
    static let pluginId = "runtime"
    let logLevel: String
    let maxConcurrent: Int

    init() { 
        self.logLevel = "info" 
        self.maxConcurrent = 1 
    }
}

let runtimeConfig = try await ConfigurationLoader.loadForPlugin(RuntimePluginConfig.self)

```

## Summary

- **Apple Container** uses a three-layer TOML configuration system with files in user, app-root, and install-root directories.
- **Precedence** follows first-match-wins: user settings in `~/.config/container/config.toml` override system defaults.
- **Schema** is defined in [`Sources/ContainerPersistence/ContainerSystemConfig.swift`](https://github.com/apple/container/blob/main/Sources/ContainerPersistence/ContainerSystemConfig.swift) with optional tables for build, container, DNS, network, registry, and plugin settings.
- **Workflow** involves editing the user config, then starting or restarting the daemon to apply changes via `ConfigurationLoader.copyConfigurationToReadOnly`.
- **Programmatic access** uses `ConfigurationLoader.load()` for system config and `loadForPlugin()` for plugin-specific settings.

## Frequently Asked Questions

### Where does Container look for config.toml files?

Container searches three locations in order: `~/.config/container/config.toml` (user), `<app-root>/config/config.toml` (app-root), and [`/usr/local/etc/container/config.toml`](https://github.com/apple/container/blob/main//usr/local/etc/container/config.toml) (install-root). According to the `ConfigurationLoader` implementation in [`Sources/ContainerPersistence/ConfigurationLoader.swift`](https://github.com/apple/container/blob/main/Sources/ContainerPersistence/ConfigurationLoader.swift), the loader merges these files using a first-match-wins strategy, where user values take precedence over system defaults.

### Do I need to specify every configuration option in config.toml?

No. All sections in [`config.toml`](https://github.com/apple/container/blob/main/config.toml) are optional. You only need to include the specific tables and keys you want to override. Missing values automatically fall back to the hard-coded defaults defined in the `ContainerSystemConfig` struct initializers, as implemented in [`Sources/ContainerPersistence/ContainerSystemConfig.swift`](https://github.com/apple/container/blob/main/Sources/ContainerPersistence/ContainerSystemConfig.swift).

### How do I apply changes after editing config.toml?

Run `container system restart` to reload the configuration. Alternatively, if the daemon is not running, `container system start` automatically copies your user configuration to the read-only app-root location via `ConfigurationLoader.copyConfigurationToReadOnly` and loads the new settings.

### Can I configure custom properties for Container plugins?

Yes. Use the `[plugin.<id>]` table syntax in your [`config.toml`](https://github.com/apple/container/blob/main/config.toml) file, then access these values in Swift by implementing the `LoadablePluginConfiguration` protocol and calling `ConfigurationLoader.loadForPlugin()`. See [`Sources/Plugins/RuntimeLinux/config.toml`](https://github.com/apple/container/blob/main/Sources/Plugins/RuntimeLinux/config.toml) for an example plugin configuration file.