Apple container: a different approach to running Linux containers on Mac
Apple has open-sourced container, a command-line tool for running Linux containers on Mac without Docker Desktop. Its architecture also differs from Docker's — each container runs in its own lightweight virtual machine. This article covers how it works, how to install it, common commands, and where the project currently stands.

For a long time, the standard way to run Linux containers on Mac has been Docker Desktop: it boots one Linux virtual machine, then packs all your containers into that VM, sharing a single kernel.
Apple's open-source project container takes a different approach: a command-line tool written in Swift that calls macOS's built-in virtualization framework directly to run Linux containers on Apple silicon, without relying on Docker Desktop or any other third-party virtualization layer.
The biggest difference from Docker: one container, one VM
container's design differs from Docker's. Docker Desktop puts all containers inside one VM; container does the opposite — it spins up a separate lightweight VM for every container it starts. According to the official docs, this gives each container "the isolation properties of a full VM" — containers can't see each other, and there's no risk of security or resource interference from sharing a kernel.
Per the official documentation, because each VM only mounts the data a container actually needs (rather than the whole shared environment), memory usage is lower than a traditional VM, and startup time is close to that of a regular container. This claim comes from the project's own documentation — how it actually performs is something to judge for yourself once you've used it.
Underneath, this is made possible by Containerization, a Swift package Apple open-sourced alongside container, which handles low-level image, container, and process management. Below that, it ties into macOS's Virtualization framework, network management, XPC communication, and launchd. Every container command you run is really the CLI talking to a background agent, container-apiserver, which in turn dispatches work to a handful of dedicated helper processes — one for images, one for networking, one for the Linux runtime.
On the image format side, there's no reinventing the wheel: it follows the OCI (Open Container Initiative) standard, so pulling from standard registries like Docker Hub, or pushing images you've built, both work as expected.
Who can use it: check the requirements first
This isn't a tool you can install on just any Mac — the requirements are strict:
- Apple silicon only; Intel Macs are not supported
- Requires macOS 26 or later; the project explicitly states it won't be maintained on earlier versions
If your dev machine is still on Intel, or hasn't been upgraded to macOS 26, this tool isn't relevant to you yet.
Installing it
The installer is downloaded from the GitHub Releases page as a signed package. Double-click it, enter your admin password, and it installs into /usr/local. After installing, you start the service manually:
1container system start
To upgrade later, stop the service first, then run the update script:
12container system stop /usr/local/bin/update-container.sh
If you want to remove it, the uninstall script offers two options — keep your data (in case you reinstall later) or wipe everything:
12345# Uninstall the app only, keep user data /usr/local/bin/uninstall-container.sh -k # Remove everything, including data /usr/local/bin/uninstall-container.sh -d
What using it actually looks like
If you're used to the Docker CLI, the experience won't feel unfamiliar — the main difference is that commands start with container instead of docker.
Building a multi-architecture image:
123container build --arch arm64 --arch amd64 \ --tag registry.example.com/fido/web-test:latest \ --file Dockerfile .
Running a container — resource limits, volume mounts, and port mapping are all supported, as you'd expect:
1234567container run --rm --cpus 8 --memory 32g big container run --volume ${HOME}/Desktop/assets:/content/assets \ docker.io/python:alpine ls -l /content/assets container run -d --rm -p 127.0.0.1:8080:8000 \ node:latest npx http-server -a :: -p 8000
Listing existing images and running containers:
12container image list container list
For machine-readable detail, pipe into jq:
1container inspect my-web-server | jq
Stopping a container and checking logs:
12container stop my-web-server container logs my-web-server
Pushing a built image to a registry:
1container image push registry.example.com/fido/web-test:latest
One detail worth noting: because each container is itself an independent VM with its own network interface, container lets you attach a container to a custom network and reach it directly by name (in the form hostname.test), rather than relying on port mapping the way traditional containers do:
1container run -d --name my-web-server --network foo --rm web-test
Where it's still rough
The project's own documentation lists two main gaps:
- Support for memory ballooning (a technique for dynamically reclaiming and returning VM memory) is still incomplete — a long-running, memory-hungry container may need periodic restarts to actually free up memory
- On earlier macOS 15 environments, network isolation, multiple networks, and IP address assignment all had limitations (which is part of why the project now requires macOS 26 outright)
Where the version stands
The project is licensed under Apache License 2.0. The current release is 1.2.0 (published 2026-07-29), two minor versions past 1.0.0, which shipped on 2026-06-09. 1.2.0 is mostly engineering work: an expanded integration test suite, the underlying Containerization dependency bumped to 0.40.1, a new --kernel-arg flag for custom kernel boot arguments, and added container ID validation plus kernel archive integrity checks for XPC requests.
Worth noting: the README still contains an older line stating that minor releases may include breaking changes "until we reach a 1.0.0 release" — even though the project has already passed that milestone, and the text hasn't been updated to reflect it. For an accurate picture of the current version, the GitHub Releases page is the more reliable source.


