I’ve used LocalWP for years and, for the most part, it’s been a great tool. It’s fairly flexible, allowing per-site PHP versions, the ability to swap between nginx and apache, XDEBUG support, live links – tons of features. Which is great until it stops working. Initially, my biggest complaint was the performance when I worked on a site with lots of plugins or an exceedingly large database, because, for all of the configurability it boasted, resources were not among the items that were configurable. More recently, about six months ago, I had issues with it even running on Ubuntu desktop.
Missing-dependency install failures and broken service detection (Local deciding MySQL, Nginx, or MailHog “aren’t installed” and failing to fix it) are the same class of problem that’s shown up in Local’s community forum across different Ubuntu releases over the years, including a years-old connectivity issue that took a while to run down to its root cause. I’m not citing these as proof Local is currently broken on Ubuntu. Both threads eventually got resolved, and I have no idea how common this class of error is on today’s release. The issue is – when this class of error hits, self-service isn’t an option.
None of that is a knock on the Local team. Linux support for a packaged Electron app juggling its own bundled services is a genuinely hard problem, and Local is solving it for a much wider range of hardware and distros than I need it to. But when I hit my version of it, my options were narrow:
- File a support request and wait for a reply
- Dig through community threads hoping someone else hit the same wall
- Restart the whole app and hope it self-healed
What I couldn’t do was open up the parts that were actually broken and fix them myself, because the internals aren’t mine to touch.
That’s the part that got to me: having no lever to pull when the tool broke.
Building My Own
Docker compose setups for local WordPress development are fairly common. It doesn’t take much effort to spin one up that works, especially for a single, relatively simple site. As you start to add complexity and work with a larger number of plugins, you need to add things like object caching and brotli/gzip compression.
I started out with a single docker compose stack running Nginx, PHP-FPM, MariaDB, Redis, and Mailhog enough to get one WordPress site running locally with some decent performance, all with logging mounted into local directories for easy access. Since I work mostly with e-commerce systems, SSL is a must for any local dev site, so that was something I created scripting for as well.
I have a few environments I work in, and with this setup, in the beginning, I had to create a few instances and only run one at a time without moving ports around, which got annoying pretty quickly. So, I decided I needed a multi site setup without having to jockey around with ports. I created shell scripts to add new sites, provisioning domains, ssl certs, and a database for each. Each site isolated into its own directory, with its own Nginx server block and shared resources.
About a month ago, I started playing around with WordPress Studio, and at first, I thought maybe all of my efforts on this Docker setup had been wasted. WP Studio seemed so elegant and fast when it came to spinning up new sites. Studio runs WordPress on WordPress Playground, a WebAssembly PHP runtime instead of a real server stack, which makes it fast to spin up with zero external dependencies. That’s great for quick plugin conflict checks, a client demo, or even some theming work. It’s not great for real debugging or running php-unit tests. Also, instead of MySql or MariaDB, it runs on Sqlite, which makes content imports a bit more challenging. There are still ways to do it. You just have to import a full site backup using the All-in-One WP Migration and Backup plugin or from LocalWP. A full site backup could be dozens of GB vs a few MB if all you want to do is import an updated DB backup.
With all the drawbacks, there are still features I admired about WP Studio that I wanted to incorporate:
- Site management CLI which can invoke the wp-cli for the current site
- Site management MCP server
- Web-based site management UI using express.js
I incorporated all of these features into my Local WP Stack. I also included a mu-plugin that gets added to each new site which adds content management MCP capabilities for each site.
What This Setup Still Can’t Do
The real tradeoff: LocalWP supports a different PHP version per site out of the box as well as allowing to switch between Apache and Nginx. My setup doesn’t. PHP version is a stack-level setting changed in the .env file and applied with a container rebuild, so every site on the stack runs the same PHP version.
For someone juggling clients on varied environments with very different configurations, that could be a real deal-breaker. For my own workflow, it hasn’t come up as a problem worth solving. If someone wanted to fork my Local WordPress project and implement that for themselves, that’s totally doable.
This project wasn’t developed with Windows users in mind, but a Windows user could probably run it under WSL if they were so inclined.
The Actual Point
I’m not arguing my setup is better than LocalWP or Studio for most people. It isn’t trying to be. Both are good tools with real teams behind them, built for a much broader audience than just me. The point is this: when a closed tool hits an edge case it doesn’t handle well on your specific setup, the only way to fix it yourself is to be holding all the pieces. Docker Compose, Nginx configs, and a database you can open directly aren’t more convenient than a polished app, until the polished app breaks in a way you can’t see into. Then they’re the only thing that is. Check out my High Performance Docker WordPress project on Github.