Working with WordPress on Windows improved with WSL2, but it is still easy to accumulate layers: Windows, Docker Desktop, another virtual machine, certificates, proxies, and tools abstracting different parts of the environment. Sometimes the environment ends up more complex than the site you were trying to build.
The idea of working with WordPress directly on WSL2 starts from a pretty simple question: How many layers are actually needed for a reliable local setup?
WSL2 is already Linux
WSL2 isn't just a Linux terminal inside Windows. It runs a real Linux kernel, has its own filesystem, and lets you run tools like Docker, PHP, MySQL, Node, or WP-CLI in an environment that's much closer to the server where the project will probably end up living.
That changes the approach quite a bit. Instead of using Windows as the main system and adding Linux as a secondary layer for specific tasks, you can treat WSL2 as the development environment and leave Windows for what it does well: browser, editor, desktop apps, and the rest of everyday work.
The filesystem matters
One of the most common mistakes is installing everything correctly on WSL2 but keeping the project inside Windows' filesystem. Something like:
/mnt/c/Users/...
It works, but it forces WSL2 to constantly operate on files that live on the other side of the Windows/Linux boundary. On WordPress projects, that friction can show up fast. Thousands of small files, Composer, npm, searching within the project, Git, and operations on wp-content all keep paying that cost over and over.
Moving projects to WSL2's native filesystem instead, for example:
~/projects/my-site usually removes most of that friction. It's not a cosmetic tweak. It changes where the work is actually happening.
Docker doesn't need that many layers either
Docker Desktop solves a lot of problems and, for certain teams, it's still an excellent tool. But if the environment is already running Linux through WSL2, you can also run Docker directly there. That removes a management layer between the project and the containers.
The result can be a pretty simple flow: WSL2 → Docker → WordPress This doesn't mean Docker Desktop is bad. It means it doesn't necessarily have to be part of every environment. If a tool isn't solving a concrete problem, it's worth asking why it's there.
Local HTTPS should be boring
HTTPS in local development tends to be one of those things that work perfectly right up until they don't. Self-signed certificates, browser warnings, manual exceptions, and local domains configured differently in every project. Tools like mkcert let you generate trusted certificates locally and skip most of that noise.
If there's also a proxy like Traefik in charge of routing the projects, each site can have a predictable address:
https://my-site.localhost and behave, from the start, in a way that's much closer to production. HTTPS stops being a task to solve per project and becomes part of the environment.
WP-CLI should live in the same world as WordPress
Another frequent source of problems shows up when WordPress runs on one PHP version and WP-CLI on another. The site runs inside a container with PHP 8.1, but the command you run from your terminal is using PHP 8.3 installed on the system.
That difference can go unnoticed until a plugin, a dependency, or a script behaves differently. A predictable environment should avoid that kind of mismatch. If WordPress runs on a specific PHP version, the tools operating on that WordPress should work in the same context whenever possible.
Fewer combinations means fewer places to check when something breaks.
Importing production is also part of the environment
Spinning up an empty WordPress is easy. The real case is usually different. We have a production site with years of content, uploads, plugins, serialized options, caches, and references to the original domain. And we need to get it running locally.
That is where a good environment starts saving time. The guide to importing WordPress without breaking serialized data covers that process in more detail. An import can involve:
- Restoring a database
- Copying
uploads - Replacing the domain
- Respecting serialized data
- Clearing caches
- Regenerating files generated by some plugins
- Adapting settings that only make sense in production
If every developer has a different recipe for doing this, the environment still depends too much on tribal knowledge.
More options don't always mean a better tool
There are excellent tools that let you configure practically any scenario. That's valuable when you genuinely need that flexibility. But it also has a cost: every new option is one more decision someone has to make, understand, and maintain. For a specific workflow, doing the opposite can be better.
A team can choose one combination—WordPress, WSL2, Docker, HTTPS, WP-CLI, and one project per environment—and optimize it. It is not the only correct way to develop WordPress, but narrowing the problem makes more automation possible.
The local environment shouldn't be a separate project
A good development environment disappears while you work. It shouldn't require thinking daily about Docker networks, certificates, runtime versions, or proxy settings. All of that still exists, but it stops being the main job. The job is changing the site, testing it, and moving on.
That's why reducing layers isn't just about performance. It also reduces decisions, differences between projects, and the number of things that can break. The goal is not to minimize components as an exercise. Every layer should solve a recognizable problem, and the environment should stop demanding attention during daily work. That criterion also led to Docal.