Local WordPress development on Apple Silicon without Docker
· 5 min read · by Lennart de Ridder
Docker on an M-series Mac is not slow because Docker is bad. It’s slow because of three things stacked on top of each other, and once you see them you stop trying to tune your way out. This post is about those three things, and about the alternative we built SiteShift on: PHP and MySQL as plain static binaries, no daemon, no VM.
Why Docker Desktop feels slow on Apple Silicon
There is a Linux VM in the middle. Containers are a Linux kernel feature. macOS doesn’t have one, so Docker Desktop runs a Linux virtual machine and your containers live inside it. Every file your editor saves has to cross that boundary before PHP in the container sees it. Docker has improved this a lot (VirtioFS, and the newer synchronised file shares), but a WordPress install is tens of thousands of small files, and wp-content/uploads is where the boundary hurts most.
Many images are still x86. An amd64 image on an arm64 Mac runs under emulation. It works, and it is several times slower than a native build. Official PHP and MySQL images have arm64 variants now; the old docker-compose.yml you copied from a 2021 tutorial may pin one that doesn’t, or a MySQL 5.7 that never got an arm64 build at all.
The daemon is always on. Docker Desktop reserves memory for its VM whether or not a container is running. On a 16 GB laptop with a browser, an editor and a Slack open, that reservation is the difference between comfortable and swapping.
None of this is a reason to stop using Docker for the things it’s good at — reproducing a production stack for a team, running six services that need to talk to each other. It is a reason to ask whether a WordPress site, which is one PHP process and one database, needs any of it.
What a static PHP binary is
Normally PHP is linked dynamically: the php executable loads shared libraries (OpenSSL, libxml, curl, the MySQL client) from the system at start-up. That’s why “just download PHP” doesn’t work — it expects a particular set of libraries in particular places, and your machine has a different set, or none.
A static build compiles all of those libraries into the executable. The result is one file, around 30 MB, that runs on any machine of the same platform without installing anything. The static-php-cli project produces exactly these builds, per PHP version, with the extensions WordPress needs — mysqli, gd, curl, mbstring, intl, zip, and so on — compiled in. MySQL 8.4 ships official macOS arm64 tarballs that are self-contained in the same way.
That means a “local WordPress environment” can be: download two binaries once, verify their checksums, put them in a folder, and start them as normal processes. No VM, no daemon, no image. PHP 8.1 and PHP 8.4 are two different files in the same folder, and switching a site between them is a matter of which one you start.
How the no-Docker stack is laid out
This is what SiteShift puts on disk. Nothing is hidden; you can walk it in Finder or Explorer (on Windows the same tree lives in your user folder).
~/.siteshift/
├── bin/ # downloaded once, checksum-verified: php per version, mysqld, wp-cli.phar
├── data/mysql/ # one MySQL data directory, one server on 127.0.0.1:13306
├── run/ logs/ # pid files, sockets and per-process logs
├── caddy/ # the router that maps <slug>.localhost to each site's PHP server
├── sites/
│ └── acme-bakery/
│ └── webroot/ # a normal WordPress install: wp-content/themes, plugins …
├── backups/acme-bakery/ # remote DB dumps taken before a push
└── secret.key # key for the encrypted vault (SSH passwords, API tokens)Each site is served by its own php -S process on a port in the 20000–39999 range, reachable as http://acme-bakery.localhost:20001. The .localhost suffix resolves to 127.0.0.1 in every modern browser and OS without touching /etc/hosts. One MySQL server runs for all sites, with a separate database and user per site, so TablePlus or mysql connect to it directly — there’s no container to tunnel into.
What you give up
Honesty section. Docker gives a team an identical stack from one file in the repo; static binaries give each machine the same checksum-verified builds, but the site itself isn’t described by a file you can commit. Docker runs anything — Redis, Elasticsearch, a mail catcher — as one more service; a binaries-based tool runs what it ships. And Docker’s Dockerfile is infinitely configurable; a bundled PHP build has the extensions it was compiled with and nothing more (the bulk build SiteShift uses covers everything WordPress and WooCommerce need, but if you depend on an unusual extension, check first).
For most WordPress work — one site, one developer, a host that already runs PHP and MySQL — those trade-offs are invisible, and what you get back is a site that starts in a second on a laptop that stays quiet.
Trying it
If you want to see the layout above with a real site in it: SiteShift creates one in about a minute and the folder is yours to inspect. If you’d rather stay in Docker, the honest recommendation is DDEV with arm64 images — it’s the best of that world, and we’ve written down where each approach wins.
Builds SiteShift and runs DeveloKey, a WordPress agency in Leiden. Every guide here comes from running client sites through the same tool.
Local WordPress with bundled PHP and MySQL, pushed to any host over SSH.
Get SiteShift — €9/mo