Mac developers are posting about replacing Docker Desktop with Apple's own container CLI. The tool shipped a stable 1.0 on June 9, 2026, and the current release is 1.5.0 (September 29). It runs Linux containers from ordinary OCI images, so most of what you pull from Docker Hub works, but it does so differently: every container gets its own lightweight virtual machine instead of sharing one big Linux VM.
This post walks through a swap you can try in about 15 minutes on an Apple silicon Mac: install, build an image, run Postgres from Docker Hub with a persistent volume, reach containers by name, and then the list of things that will send you back to Docker.
How it differs from Docker Desktop
Docker Desktop starts one Linux VM and runs all your containers inside it, separated by namespaces. Apple's container creates a small VM per container. Two consequences follow:

- Isolation. To escape a container, code has to get past a hypervisor, not only kernel namespaces. That is a real gain if you run code you did not write, such as a coding agent's output or a dependency you have not audited.
- Each container has its own resources. By default a container gets 1 GB of RAM and 4 CPUs; change that per container with
--memoryand--cpus. The image builder runs with 2 CPUs and 2048 MB by default.
Requirements: Apple silicon and macOS 26. Intel Macs are not supported, and the maintainers say they will not address issues that cannot be reproduced on macOS 26.
Install and start
Download the installer package from the releases page, install it, then start the system service:

container system startOn first start it offers to install the recommended Linux kernel (a Kata Containers build). Answer Y. Check that everything is up:
container ls --allAn empty table is the right answer. container --help lists every command; most have the Docker-style names you expect (run, build, exec, logs, stop).
Build and run an image
This is the example from Apple's own tutorial: a Python web server that serves one HTML page. Save it as Dockerfile:
FROM docker.io/python:alpine
WORKDIR /content
RUN apk add curl
RUN echo '<!DOCTYPE html><html><head><title>Hello</title></head><body><h1>Hello, world!</h1></body></html>' > index.html
CMD ["python3", "-m", "http.server", "80", "--bind", "0.0.0.0"]Build it, then run it in the background:
container build --tag web-test --file Dockerfile .
container image list
container run --name my-web-server --detach --rm web-testEach container gets its own IP address on a host network. container ls shows it; open that address in the browser (the tutorial's example is http://192.168.64.3). You can also publish a port to localhost the Docker way:
container run --name web2 --detach --rm --publish 127.0.0.1:8080:80 web-test
curl http://127.0.0.1:8080The usual inspection commands work as you would guess:
container logs --follow my-web-server
container exec --tty --interactive my-web-server sh
container stats my-web-server
container stop my-web-server web2Postgres from Docker Hub, with a volume
The official Postgres image runs unchanged. Use a named volume rather than a bind mount: the project's docs say named volumes give better I/O than bind mounts. Set PGDATA to a subdirectory, the standard workaround when the mounted volume root is not empty.
container volume create pgdata
container run --name pg --detach \
--env POSTGRES_PASSWORD=dev \
--env PGDATA=/var/lib/postgresql/data/pgdata \
--volume pgdata:/var/lib/postgresql/data \
--publish 127.0.0.1:5432:5432 \
--memory 2g \
docker.io/library/postgres:17Check it from inside the container:
container exec pg psql -U postgres -c 'select version();'Your app on the Mac connects to 127.0.0.1:5432 as before. Stop and delete the container and the data stays in the volume; container volume list shows it.
One difference from Docker to know before you script cleanup: anonymous volumes are not removed when a container started with --rm exits. And container volume prune deletes unused volumes and their contents immediately, with no way back.



