How Container Handles Container-to-Container Networking on macOS
Container uses macOS vmnet to create isolated virtual networks where containers cannot communicate directly; all inter-container traffic must route through the host via published ports or alternative IPC mechanisms.
The apple/container runtime leverages the macOS vmnet framework to provide virtual networking for containers. Unlike Linux-based container runtimes that allow direct bridge communication between containers, the vmnet implementation in macOS intentionally isolates each container's network stack. This architectural constraint means that containers on the same virtual network cannot reach each other directly, requiring developers to use host-mediated networking patterns.
How Container Networking Works Under the Hood
When you execute container system start, the runtime initializes a vmnet-based bridge network named default. This network is managed by the XPC service implemented in Sources/Plugins/NetworkVmnet/NetworkVmnetHelper.swift, which interfaces with the macOS vmnet framework (available in macOS 15 and later).
Containers attached to this default bridge receive IP addresses from a shared CIDR block—typically something like 192.168.64.0/24—but the vmnet framework enforces strict isolation between endpoints. According to the technical overview in docs/technical-overview.md (lines 65-68), the framework "can only provide networks where the attached containers are isolated from one another." This is a fundamental limitation of the macOS virtualization layer, not a design choice of the Container runtime itself.
Why Direct Container-to-Container Communication Is Blocked
The isolation occurs at the hypervisor level. When two containers attach to the default network, they each receive unique MAC addresses and IP addresses, but the vmnet bridge does not forward Layer 2 traffic between them. As a result:
- Ping and TCP connections between container IPs fail by default
- Service discovery via DNS names resolves to isolated endpoints that cannot route to each other
- Shared network interfaces do not imply shared broadcast domains
This behavior differs fundamentally from Docker or Podman on Linux, where attached containers can freely communicate over the bridge.
Working Around the Isolation Limitation
Since the runtime does not provide direct container-to-container networking, you must use one of the following host-mediated approaches:
Publishing Ports Through the Host
The most common pattern is to expose services on the host's network namespace and have other containers connect via the host's IP address. The runtime provides the host.docker.internal pseudo-hostname to facilitate this.
# Start an HTTP server in container A and publish port 8080 on the host
container run -d --name api \
--network default,mac=02:42:ac:11:00:02 \
-p 8080:80 \
nginx:latest
# From container B, access the service via the host
container run --rm \
--network default,mac=02:42:ac:11:00:03 \
curlimages/curl:latest curl http://host.docker.internal:8080
In this example, container B reaches container A not through the virtual bridge, but by routing traffic via the macOS host's loopback interface.
Creating User-Defined Networks (macOS 26+)
On macOS 26 and later, you can create isolated networks using the container network create command, implemented in Sources/ContainerCommands/Network/NetworkCreate.swift. However, these networks follow the same isolation rules as the default network.
# Create an isolated network (still uses vmnet)
container network create foo
# Attach containers to the same user-defined network
container run -d --name db --network foo postgres:15
container run -d --name web --network foo \
-e POSTGRES_HOST=host.docker.internal \
my-web-app:latest
Even when attached to the same user-defined network, containers cannot communicate directly. The POSTGRES_HOST environment variable must point to host.docker.internal (or the host's actual IP) rather than the container name db, as name resolution resolves to isolated endpoints.
Using Shared Volumes for IPC
For high-performance inter-process communication that bypasses the network stack entirely, use shared volumes. This approach is documented in docs/how-to.md (lines 306-326) and involves mounting a common directory between containers to use Unix sockets or file-based signaling.
Key Source Files
The networking implementation is spread across Swift source files and documentation:
docs/technical-overview.md— Describes the vmnet isolation model and architectural constraintsdocs/how-to.md— Provides practical examples of port publishing and network creationSources/Plugins/NetworkVmnet/NetworkVmnetHelper.swift— Manages the XPC service that creates and configures vmnet bridgesSources/ContainerCommands/Network/NetworkCreate.swift— Implements the CLI command for creating user-defined networks and selecting thecontainer-network-vmnetplugin
Summary
- Container uses macOS vmnet to create virtual bridge networks that isolate containers from one another by design.
- Direct communication is impossible between containers on the same network; the vmnet framework explicitly prohibits Layer 2 forwarding between attached interfaces.
- Use host-mediated networking by publishing ports (
-p) and connecting viahost.docker.internal, or rely on shared volumes for IPC. - User-defined networks (macOS 26+) provide organizational isolation but do not enable direct container-to-container connectivity.
Frequently Asked Questions
Can containers talk to each other directly on the default network?
No. Containers attached to the default vmnet bridge are explicitly isolated from one another by the macOS vmnet framework. Even though they share the same CIDR block, the bridge does not forward traffic between container interfaces.
How do I enable communication between containers in the Container runtime?
You must route traffic through the host. Publish the service port using the -p flag when starting the server container, then have client containers connect to host.docker.internal:<published_port>. Alternatively, use shared volumes for file-based IPC if network latency is a concern.
What is the difference between default and user-defined networks?
Both network types use the same vmnet-based isolation model and do not allow direct container communication. User-defined networks (created via container network create in Sources/ContainerCommands/Network/NetworkCreate.swift) provide logical separation for organizational purposes and are available only on macOS 26+, but they maintain the same isolation constraints as the default network.
Why does Container use vmnet instead of traditional bridge networking?
The Container runtime is designed specifically for macOS virtualization, where vmnet is the supported framework for creating virtual network interfaces in the hypervisor. This framework provides automatic NAT and DHCP integration with the host's network stack, but it imposes the isolation limitation described in docs/technical-overview.md as a security feature of the macOS virtualization layer.
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 →