Docker on macOS runs every container inside a Linux virtual machine — Macs can't run Linux containers natively. That single fact is the root of most Docker-on-Mac complaints: the VM holds memory whether containers are busy or not, file syncing between macOS and the VM makes I/O-heavy workloads (a Laravel vendor directory, a node_modules install) noticeably slower than native, and a cold start means booting a VM before your app boots. If your local work is standard web development — PHP, Node, a database, a dev server — you can skip the VM entirely and run everything natively.
What Docker is actually buying you locally
Be honest about the trade before replacing it. For local development, Docker typically provides four things: version isolation (project A on PHP 8.2, project B on 8.4), service provisioning (a database without installing one), parity with a production container image, and a disposable environment you can destroy and recreate. Only one of those — byte-for-byte image parity — actually requires containers. The other three are properties any managed environment can provide, without a VM in the middle.
The native alternatives on a Mac
- Faster container runtimes (OrbStack, Colima) keep the Docker model but slim the VM. Right answer when you genuinely need containers — Linux-only dependencies, production images, Kubernetes — and just want less overhead.
- Homebrew services by hand — install PHP, Node, MySQL directly. Fully native, but version juggling across projects (multiple PHP versions, conflicting ports, hand-edited configs) is exactly the pain that pushed people to Docker.
- Managed native environments — apps that run runtimes and services as native processes and handle versioning for you: Laravel Herd (PHP-first), ServBay, MAMP (the long-running classic), and PortBay. No VM, native filesystem speed, instant starts.
What the managed-native approach looks like
PortBayis the version of this we build: a free, open-source macOS app where adding a project folder and pressing play provisions everything Docker Compose would have — and the pieces it wouldn't:
- Runtimes per project, no VM: PHP-FPM versions side by side, Node pinned per project, auto-detected from the framework. Processes run natively, so starts take seconds and file I/O is just the filesystem.
- Databases in one click: per-project MySQL or PostgreSQL with credentials injected into
.env— the docker-composedb:block, minus the YAML and the VM memory tax. - Things Compose never gave you: trusted HTTPS on a real
.testdomain, local email capture, one-click public tunnels, and a task board that dispatches AI coding agents into that running environment.
The honest caveat: native means macOS processes, not Linux ones. You give up image-level parity with a Linux production host. For most web work — where “parity” really means same language version, same database engine, same environment variables — that's a difference you stopped noticing years ago. If your app depends on Linux-specific behavior, keep a container runtime for that project.
Decision guide
| Your situation | Best fit |
|---|---|
| Production runs Linux-only deps; you ship the image | Keep containers — use OrbStack/Colima for speed |
| Microservices you must run as a fleet locally | Containers, or a hybrid (apps native, fleet in Docker) |
| PHP / Node web apps + a database + a dev server | Managed native environment — no VM needed |
| One simple project, no version conflicts | Homebrew is fine; tooling would be overhead |
| AI coding agents need to run and verify the app | Native environment with HTTPS, DB and a board — PortBay |
Migrating off Docker for a typical web project
- Inventory the compose file. Most web projects reduce to: app container (a runtime), database, maybe Redis or Mailhog.
- Add the project folder to PortBay and press play — runtime, web server, HTTPS and the
.testdomain come up automatically. - Create the database in one click and export/import your data (
mysqldumpfrom the container, restore into the native DB; connection string is already in.env). - Mail capture is built in — delete the Mailhog block. Tunnels replace ngrok containers.
- Keep the Dockerfile for CI and production builds. Local dev and deployment packaging don't have to share machinery.
Imports from Herd, ServBay and MAMPare automated in one click if you're consolidating from another native tool rather than from Docker itself.
