How to Create Custom Networks for macOS 26+ Containers with Apple Container
Apple Container creates isolated custom networks using the vmnet-based container-network-vmnet plugin, accessible via CLI commands or the NetworkClient Swift API.
Apple Container provides a built-in networking stack for macOS 26 and later that abstracts virtual machine networking through the container-network-vmnet plugin. When you execute container system start, the framework initializes a default network automatically, but you can also define completely isolated virtual LANs for specific workloads. Creating custom networks for containers on macOS 26+ ensures traffic segmentation and network isolation between different groups of containers.
Architecture of Custom Container Networks
The XPC Communication Flow
The architecture follows a CLI → XPC → Container-API-Server pattern. When you execute a network command, the CLI parses arguments and builds an XPC message sent to the container-apiserver Mach service (com.apple.container.apiserver). The client implementation resides in Sources/Services/ContainerAPIService/Client/NetworkClient.swift, specifically within the NetworkClient class (lines 24-33) that handles the transport layer.
The container-network-vmnet Plugin
The server delegates network creation to the container-network-vmnet plugin. This plugin creates a vmnet interface, assigns the requested IPv4 and IPv6 CIDR blocks, and registers the network in the server's state. Each network receives its own vmnet interface, ensuring complete traffic isolation between networks. The plugin registration and loading logic is handled by Sources/ContainerPlugin/PluginLoader.swift.
Creating Custom Networks via CLI
Use the container network create command to define isolated networks with specific subnet ranges.
Create a network with custom subnets:
# Create a network called "foo" with explicit IPv4 and IPv6 CIDRs
container network create foo \
--subnet 192.168.100.0/24 \
--subnet-v6 fd00:1234::/64
Verify the network exists:
container network list
#> NETWORK STATE SUBNET
#> default running 192.168.64.0/24
#> foo running 192.168.100.0/24
Attach containers to your custom network:
container run -d --name web --network foo --rm web-test
Clean up resources:
container stop web
container network delete foo
Programmatic Network Management with NetworkClient
For Swift applications, interact directly with the XPC service using NetworkClient from Sources/Services/ContainerAPIService/Client/NetworkClient.swift.
import ContainerResource
import ContainerPlugin
let client = NetworkClient()
// Define a custom network configuration
let config = NetworkConfiguration(
id: "my-custom-net",
name: "my-custom-net",
subnet: "192.168.200.0/24",
subnetv6: "fd00:abcd::/64",
internal: false,
labels: [:],
options: [:],
plugin: "container-network-vmnet"
)
// Create the network using the create method (lines 67-84)
let network = try await client.create(configuration: config)
print("Created network \(network.id) with IPv4 \(network.subnet)")
// List all networks using the list method (lines 91-104)
let all = try await client.list()
print("Current networks: \(all.map(\.id))")
// Delete the network when done
try await client.delete(id: config.id)
The create method sends a .networkCreate route request, while list invokes the networkList XPC route. The delete method (lines 21-33) submits a networkDelete request after verifying no containers remain attached.
Network Lifecycle and Isolation
Persistent State and Pruning
Networks persist while the API server runs. You can remove unused networks using container network delete <name>, which executes the delete method in NetworkClient.swift after validating zero container attachments. To bulk-remove unused networks, use container network prune, which preserves the built-in default network while deleting all unattached custom networks, as documented in docs/command-reference.md.
Traffic Isolation Guarantees
Each custom network operates as a completely isolated virtual LAN. Containers attached to one network cannot see traffic on any other network, including the built-in default network. This isolation is enforced at the vmnet interface level, as described in docs/how-to.md under the "Create and use a separate isolated network" section.
Summary
- Apple Container uses the container-network-vmnet plugin to create vmnet-based networks on macOS 26+.
- The NetworkClient class in
Sources/Services/ContainerAPIService/Client/NetworkClient.swiftimplements XPC communication with thecontainer-apiserverMach service. - Custom networks support explicit IPv4 and IPv6 CIDR assignment via CLI flags or the
NetworkConfigurationstruct. - Each network receives a dedicated vmnet interface, ensuring complete traffic isolation between container groups.
- Networks persist until explicitly deleted or pruned, with the default network remaining protected during cleanup operations.
Frequently Asked Questions
What is the default network created by Apple Container?
When you run container system start, the framework automatically creates a network named default with a predefined subnet (typically 192.168.64.0/24). This network is initialized in NetworkClient.swift (lines 43-45) and is protected from pruning operations, serving as the primary network for containers that do not specify a --network flag.
Can containers communicate across different custom networks?
No. Containers attached to different networks are completely isolated. The container-network-vmnet plugin creates separate vmnet interfaces for each network, preventing cross-network traffic at the virtualization layer. This design follows the standard container networking model where explicit bridge or routing configuration is required for inter-network communication.
How do I specify which network plugin to use when creating a network?
By default, Apple Container uses the container-network-vmnet plugin. When using the Swift API, set the plugin parameter in NetworkConfiguration to "container-network-vmnet". The CLI currently uses this plugin automatically, with plugin selection handled internally by the PluginLoader in Sources/ContainerPlugin/PluginLoader.swift.
What happens if I try to delete a network that still has running containers?
The deletion operation fails. The NetworkClient.delete method (implemented in NetworkClient.swift lines 21-33) validates that no containers are attached to the network before submitting the networkDelete XPC request to the server. You must stop and remove all attached containers before the network can be deleted.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →