How to Configure Memory and CPU for Containers in Apple's Container Runtime

Configure memory and CPU for containers using command-line flags (--cpus, --memory), the config.toml configuration file, or the Swift API, with defaults defined in ContainerSystemConfig.swift and validated at runtime in ContainersService.swift.

The apple/container repository provides a Swift-based container runtime that allows precise control over resource allocation. Understanding how to configure memory and CPU settings ensures optimal performance for both development environments and production workloads.

Configuration Layers

The container runtime applies CPU and memory settings through three distinct layers, defined in ContainerSystemConfig.swift and enforced across the system.

Default Values

When no overrides are specified, the runtime uses hard-coded defaults defined in the ContainerConfig and BuildConfig structs within Sources/ContainerPersistence/ContainerSystemConfig.swift. Regular containers default to 4 CPUs and "1g" (1 GiB) of memory, while the builder VM defaults to 2 CPUs and "2048mb" (2 GiB) of memory.

These values are loaded from the [container] and [build] sections of the config.toml file if present, falling back to the code-defined constants when keys are missing.

Command-Line Overrides

Per-container overrides take precedence through the --cpus and --memory flags. In Sources/Services/ContainerAPIService/Client/Flags.swift, the Resource struct parses these flags as Int64? and String? respectively. The Parser.swift file then converts memory strings to byte counts using Parser.memoryStringAsMiB and Parser.memoryStringAsBytes, which rely on Measurement.parse from Measurement+Parse.swift.

Runtime Validation

Before launching, ContainersService.swift validates that requested memory meets the minimum threshold of 200 MiB. If configuration.resources.memoryInBytes is below this value, the service returns an explicit error and prevents container creation.

Memory Format Specification

Memory values use a MemorySize format parsed by Measurement.parse in Sources/ContainerPersistence/Measurement+Parse.swift. The format accepts binary units (powers of 1024) with these case-insensitive suffixes:

  • "b" – bytes
  • "k" – KiB (1024 bytes)
  • "mb" – MiB (1024 KiB)
  • "g" – GiB (1024 MiB)
  • "t" – TiB (1024 GiB)

Plain integers without suffixes are interpreted as bytes. For example, "4g" converts to approximately 4,294,967,296 bytes (4 × 1024³).

CPU Handling

CPU allocation uses plain integers representing virtual CPUs. The --cpus flag maps directly to an Int64 value with no unit suffix required. The system stores this as configuration.resources.cpus and applies it to the container's cgroup limits. Unlike memory, CPU values undergo only basic integer parsing without additional runtime validation beyond type checking.

Practical Configuration Examples

1. Command-Line Resource Allocation

Use the --cpus and --memory flags to set resources for a specific container run:

container run --cpus 2 --memory 4g myimage:latest

This command allocates 2 vCPUs and 4 GiB of RAM, overriding any default settings.

2. Permanent Defaults in config.toml

Set system-wide defaults by editing $HOME/.config/container/config.toml:

[container]
cpus   = 6
memory = "8g"

[build]
cpus   = 4
memory = "4096mb"

The runtime reads this file via ContainerSystemConfig, applying these values to all new containers and builder VMs unless overridden by flags.

3. Swift API Configuration

Programmatically configure resources using the ContainerAPI module:

import ContainerAPI

let resources = Resources(
    cpus: 3,
    memoryInBytes: try MemorySize("2g").measurement.converted(to: .bytes).value
)

let config = ContainerConfiguration(resources: resources)
try client.create(config)

The MemorySize initializer uses the same parsing logic as the CLI, ensuring consistency between programmatic and command-line interfaces.

4. Inspecting Resource Usage

Monitor actual resource consumption against configured limits:

container stats mycontainer

Output displays current CPU percentage and memory usage against limits (e.g., Memory usage: 1.2 GiB / 8 GiB), sourced from ContainerStats.swift which tracks memoryUsageBytes and memoryLimitBytes.

Summary

  • Defaults: 4 CPUs and 1 GiB memory for containers, 2 CPUs and 2 GiB for builder VMs, defined in ContainerSystemConfig.swift
  • Configuration methods: Command-line flags (--cpus, --memory), config.toml settings, or Swift API Resources struct
  • Memory format: Binary units (b, k, mb, g, t) parsed by Measurement.parse with a 200 MiB minimum enforced by ContainersService.swift
  • CPU format: Plain integers representing vCPUs, stored as Int64 without additional validation

Frequently Asked Questions

What is the minimum memory requirement for containers?

The runtime enforces a minimum memory allocation of 200 MiB (approximately 209,715,200 bytes). If you specify a value below this threshold through any configuration method, ContainersService.swift rejects the request with a validation error before creating the container.

How does the memory suffix parsing work in container configuration?

The runtime uses Measurement.parse from Measurement+Parse.swift to interpret memory strings as binary units (powers of 1024). Suffixes are case-insensitive: "k" represents KiB, "mb" represents MiB, "g" represents GiB, and "t" represents TiB. Plain integers without suffixes are interpreted as raw bytes, ensuring flexibility across different configuration interfaces.

Where are the default CPU and memory values defined?

Default values reside in Sources/ContainerPersistence/ContainerSystemConfig.swift within the ContainerConfig and BuildConfig structs. Regular containers default to 4 CPUs and "1g" memory, while the builder VM uses 2 CPUs and "2048mb" memory. These hard-coded values serve as fallbacks when the config.toml file lacks explicit entries or when command-line flags are omitted.

Can I configure resources programmatically instead of using CLI flags?

Yes, the Swift API exposed in ContainerAPI allows direct configuration of the Resources struct. You can specify CPU counts as integers and memory as parsed MemorySize objects converted to bytes. This approach uses the same underlying validation and parsing logic as the command-line interface, ensuring consistent behavior across automation scripts and manual operations.

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 →