If you are a professional WordPress developer in 2026, Docker is your best friend. Gone are the days of manually installing PHP versions on your Mac or fighting with Windows-specific server bugs. Docker has become the common language of development environments, and knowing it well is part of the job for anyone working in the WordPress ecosystem today.
This guide covers Docker applied to WordPress development: from the basics and the official wordpress image to Compose, wp-env, debugging, CI/CD and migrating away from MAMP or LocalWP. The technical details come from the official Docker documentation, the wordpress image page on Docker Hub, MariaDB and the WordPress developer handbook, linked in each section.
Why use Docker for WordPress development
The “works on my machine” excuse stops working once the environment lives in versioned files. Containerization ensures consistency between environments, and that shift has changed how WordPress teams collaborate and ship software.
Parity between local and production environments
Your local container can use the same Linux distribution, PHP version, and MySQL configuration as your production server. That cuts down the most frustrating category of bugs: the ones that only show up in production. When you develop inside a Docker container built from the same image the server runs, code that works on your laptop behaves the same on the staging server and in production.
Environment parity goes beyond software versions. It covers network configuration, environment variables and file permissions. With Docker, every team member works in an identical environment, whether the host operating system is macOS, Windows or Linux.
Several PHP versions in isolated projects
Project A needs PHP 8.4, and Project B needs PHP 7.4? No problem. Each project lives in its own “bubble” and never conflicts with others. This level of isolation was hard to get with traditional tools like MAMP or XAMPP, where changing the PHP version affected every project at once.
Docker isolation also protects your host operating system. PHP extensions, system libraries and project dependencies stay separate. If one project needs an experimental PHP extension or an unusual server configuration, you can add it without risk to your other projects.
A reproducible environment from files versioned in Git
Every Docker environment is defined by configuration files versioned in Git. A new team member clones the repository, runs one command and has the environment working, with no step-by-step setup guide that slowly goes out of date. The environment documentation lives in the project code itself.
WordPress Docker Compose setup
Docker Compose is the tool that coordinates multiple containers. A typical 2026 WordPress setup includes several services that work together as a complete development environment.
Which services WordPress needs in Docker Compose
- WordPress (PHP-FPM or Apache): the engine that runs the WordPress PHP code.
- Nginx: the web server in front of PHP-FPM, if you choose the
fpmvariant. - MariaDB/MySQL: the database that stores all the content.
- Redis: the object cache, worth adding if the project uses it in production.
- Mailpit: to catch outgoing emails during testing.
# compose.yaml snippet with the FPM variant
services:
db:
image: mariadb:11.4
volumes:
- db_data:/var/lib/mysql
wordpress:
image: wordpress:php8.4-fpm
depends_on:
- db
volumes:
db_data:The fpm variant ships no web server, so it needs an Nginx container that passes PHP requests to it. If you do not want to configure Nginx, the Apache variant (wordpress:php8.4-apache) serves WordPress directly on port 80 of the container.
Bind mounts or named volumes for WordPress
Volumes in Docker Compose matter a lot for WordPress development. You need to mount your themes and plugins directory to edit code live, while database data must persist in named volumes so nothing is lost when the container restarts.
The right strategy balances performance and function. For files you edit often (themes, your own plugins), use bind mounts. For data that only needs to persist (database, uploads), use named Docker volumes. The official image documentation gives the paths: themes go in /var/www/html/wp-content/themes/ and plugins in /var/www/html/wp-content/plugins/.
Credentials in .env files with Docker Compose
Secret handling matters even locally. Use .env files for database credentials and API keys, and make sure those files are listed in your .gitignore. Docker Compose reads the .env file in the project directory and substitutes variables such as ${DB_PASSWORD} inside compose.yaml, which keeps sensitive configuration apart from versioned code.
Environment variables of the official WordPress image
The wordpress image on Docker Hub generates its own wp-config.php from environment variables. According to the official image page, these are the ones it reads:
| Variable | What it does |
|---|---|
WORDPRESS_DB_HOST | Service name or host of the database |
WORDPRESS_DB_USER and WORDPRESS_DB_PASSWORD | Database credentials |
WORDPRESS_DB_NAME | Database name, which must already exist |
WORDPRESS_TABLE_PREFIX | Table prefix instead of wp_ |
WORDPRESS_AUTH_KEY and the other keys and salts | If you leave them out, the image generates random values |
WORDPRESS_DEBUG | Any non-empty value turns on WP_DEBUG |
WORDPRESS_CONFIG_EXTRA | Extra PHP code evaluated inside wp-config.php |
The detail that wastes the most time: the WordPress container does not create the database named in WORDPRESS_DB_NAME. The database container creates it, through MARIADB_DATABASE in MariaDB or MYSQL_DATABASE in MySQL. If the two names differ, WordPress shows a connection error even with correct credentials.
WORDPRESS_CONFIG_EXTRA is for constants the image does not expose, for example WP_ALLOW_MULTISITE or WP_ENVIRONMENT_TYPE. Whatever you put there runs through eval(), so keep it short and versioned with the rest of the configuration.
How to make WordPress wait for MariaDB in Docker Compose
A plain depends_on is not enough. The Compose documentation on startup order explains that Compose waits for the dependency container to be running, not for it to be ready to accept connections. MariaDB needs a few seconds to initialise on first start, and WordPress can boot earlier and fail to connect.
The fix is a healthcheck on the database and condition: service_healthy on WordPress. The official MariaDB image includes a healthcheck.sh script for this, and the MariaDB documentation publishes an example with WordPress. Adapted for a development environment it looks like this:
services:
db:
image: mariadb:11.4
environment:
MARIADB_DATABASE: wordpress
MARIADB_USER: wordpress
MARIADB_PASSWORD: ${DB_PASSWORD}
MARIADB_RANDOM_ROOT_PASSWORD: '1'
volumes:
- db_data:/var/lib/mysql
healthcheck:
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
start_period: 10s
interval: 10s
timeout: 5s
retries: 3
wordpress:
image: wordpress:php8.4-apache
ports:
- "8080:80"
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_NAME: wordpress
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: ${DB_PASSWORD}
WORDPRESS_DEBUG: '1'
volumes:
- wp_data:/var/www/html
- ./my-theme:/var/www/html/wp-content/themes/my-theme
depends_on:
db:
condition: service_healthy
volumes:
db_data:
wp_data:With this file, docker compose up -d starts the database, waits for the healthcheck to pass and only then starts WordPress on http://localhost:8080. Your own theme is a bind mount, and the rest of WordPress sits in the wp_data volume.
WordPress Docker image variants: apache, fpm, alpine and cli
The official image is published in several variants. Tags combine the WordPress version, the PHP version and the type, for example php8.4-apache, php8.4-fpm, php8.4-fpm-alpine or cli.
- apache: WordPress and Apache in one container. The most direct option for local development.
- fpm: PHP-FPM only, meant to sit behind Nginx or another proxy.
- fpm-alpine: the same on Alpine Linux, with a smaller image.
- cli: WP-CLI without a web server, for running
wpcommands against an existing install.
The cli variant has a trap documented on Docker Hub: it is based on Alpine and its www-data user has UID 82, while the Debian-based variants use UID 33. Running wordpress:cli against a Debian install usually needs --user 33:33, and sometimes -e HOME=/tmp, so WP-CLI can write to the files.
How to add PHP extensions to the official image
The image does not include extra PHP extensions, even when popular plugins need them. Docker Hub gives the example that the image cannot send email on its own. To add extensions you build your own image with FROM wordpress:... and follow the instructions of the php image. To change directives like upload_max_filesize, copying a custom.ini into $PHP_INI_DIR/conf.d/ is enough:
FROM wordpress:php8.4-apache
COPY custom.ini $PHP_INI_DIR/conf.d/If you want themes or plugins baked into the image for several installs, the documentation says to copy them to /usr/src/wordpress/, which is copied to /var/www/html/ on the container’s first start.
wp-env, the official WordPress Docker environment
If you build plugins or themes and do not need to reproduce a specific server, wp-env saves you from writing compose.yaml by hand. It is a Node package maintained in the Gutenberg repository that runs Docker underneath. You install it with npm -g i @wordpress/env and start it with wp-env start from the plugin folder.
The environment runs at http://localhost:8888 with the user admin and the password password. Configuration goes in a .wp-env.json file at the project root:
{
"$schema": "https://schemas.wp.org/trunk/wp-env.json",
"core": null,
"phpVersion": "8.3",
"plugins": [ "." ],
"config": {
"WP_DEBUG_LOG": true
}
}core set to null uses the latest stable WordPress release, phpVersion pins the PHP version and plugins lists the plugins to install and activate. There are also themes, mappings for mounting directories, port (8888 by default), testsPort (8889) and mariadbVersion.
Composer, PHPUnit and WP-CLI come with the cli container: wp-env run cli wp plugin list or wp-env run cli --env-cwd=wp-content/plugins/my-plugin composer install. Xdebug is installed but off, and you turn it on with wp-env start --xdebug. The documentation also describes an experimental mode, wp-env start --runtime=playground, which runs WordPress in WebAssembly without Docker, on SQLite and without the run command.
The practical difference from Compose: wp-env picks the architecture for you. For a plugin that is faster. To reproduce a production server with Nginx, Redis and an exact MariaDB version, Compose is still the right tool.
VS Code dev containers for WordPress
Many developers no longer install PHP on their laptops. They use VS Code Dev Containers, which change how you work with the editor.
How a dev container works in VS Code
You open your project folder, and VS Code detects the .devcontainer folder, boots Docker and connects the IDE directly into the container. VS Code extensions, command line tools and editor settings all run inside the container.
Extensions and linters preconfigured in the container
A configured workspace for every project, as soon as you open the folder. Whether a developer joined the team five minutes ago or five years ago, the environment is identical for everyone. PHP extensions, linters, code formatters and debugging tools are defined in the repository.
Dev containers for distributed teams
For WordPress agencies with distributed teams, dev containers remove a common source of friction: differences between local environments. Whoever opens the repository gets the same toolchain, without a “let’s set up your laptop” call.
Docker performance on Mac and Windows
Docker used to be slow on non-Linux systems, because project files cross a virtual machine boundary. Docker Desktop now offers several ways to cut that cost.
How to enable VirtioFS in Docker Desktop
On macOS, pick VirtioFS as the file sharing implementation in Docker Desktop settings. The Docker Desktop settings documentation states that VirtioFS has reduced the time taken to complete filesystem operations by up to 98%. It replaces the earlier options, osxfs and gRPC FUSE.
Synchronized file shares for large repositories
For very large projects, Docker Desktop offers Synchronized file shares: it keeps a synchronized cache of the host files on an ext4 filesystem inside the virtual machine. Docker recommends it for repositories with 100,000 files or more, and it is available on the Pro, Team and Business subscriptions. A WordPress install with a large node_modules inside the theme can get close to that number.
How much RAM Docker Desktop uses
The Docker Desktop virtual machine holds memory while it is running. Resource Saver mode stops it when no containers have been running for 5 minutes (adjustable), and Docker cites savings of 2 GB or more of host memory and CPU.
Docker vs LocalWP vs DDEV for WordPress
| Tool | Audience | Flexibility | Scalability |
|---|---|---|---|
| Docker | Professional Devs | Very high | High |
| LocalWP | Freelancers/Beginners | Low | Medium |
| MAMP/WAMP | Legacy Users | None | Low |
| DDEV / Lando | Docker Power-Users | High | High |
Docker Compose compared with DDEV and Lando
DDEV and Lando simplify Docker for WordPress developers. They ship preset configurations and short commands that lower the learning curve. When you need full control over every piece of the infrastructure, Compose with your own file is still the most flexible option.
When to choose DDEV and when Docker Compose
The choice depends on your experience and the project. If you are new to containers, DDEV has a gentler learning curve. If you run several projects with different infrastructure needs, Docker Compose with your own configurations gives you more room.
Security in Docker environments for WordPress
Docker isolates by default, but configuration decides how much protection you get.
Containers without root and up-to-date images
Avoid running processes as root inside your containers when there is no need. Keep base images updated to get security patches; the wordpress image documentation itself reminds you to rebuild and redeploy regularly. Scan your images for known vulnerabilities with tools such as Docker Scout or Trivy.
Separate Docker networks per project
Compose creates its own network for each project. Keep that separation and do not attach containers from different projects to the same network without a reason, so a breach in one does not reach the others.
Docker secrets and .env files for passwords
Never put credentials directly in your Dockerfile or compose.yaml. The wordpress image accepts the _FILE suffix on its variables: WORDPRESS_DB_PASSWORD_FILE=/run/secrets/db_password reads the password from a file instead of a variable. Compose mounts each secret at /run/secrets/<name> inside the container, according to its secrets guide, which adds one limit: secrets only work in Linux containers.
How to set up WordPress CI/CD with Docker
The biggest win with Docker is that your CI/CD pipeline (GitHub Actions, GitLab CI) can use the same images you use locally. That consistency removes a whole category of deployment bugs.
Steps of a CI/CD pipeline with Docker
- Run PHPUnit tests in the container to check backend logic.
- Run Cypress or Playwright end-to-end tests against the container.
- Deploy the stable image to your production cluster (Kubernetes/Swarm).
Private Docker image registry for WordPress
Teams that build their own WordPress images keep them in a private container registry. Those images carry the needed PHP extensions, development tools and project configuration, so a new team member pulls the image instead of building it.
Docker Hub also describes a static deployment mode: build an image with WordPress, the theme and the plugins inside /usr/src/wordpress, run it with --read-only and tmpfs for /tmp and /run, and update by deploying a new image instead of relying on automatic updates.
WordPress on Kubernetes or Docker Swarm
For high-traffic WordPress sites, orchestration with Kubernetes or Docker Swarm lets you scale with demand. When traffic rises during campaigns or sales events, new containers start to absorb the load.
How to debug WordPress in Docker
Debugging WordPress inside containers takes a few techniques that differ from traditional local development.
Xdebug inside containers
Setting up Xdebug in a container needs attention to networking: the container has to reach the IDE listening on the host. Many dev container setups already ship Xdebug, wp-env turns it on with --xdebug, and in your own image you need to install the extension and configure the client host and port.
How to read logs with docker compose logs
Docker gives central access to the logs of every service. Use docker compose logs to see combined output from WordPress, Nginx, MariaDB and Redis, or docker compose logs -f wordpress to follow one service. With WORDPRESS_DEBUG on, PHP notices show up in that same output. In production, tools such as Grafana and Prometheus provide monitoring dashboards.
Query Monitor and Blackfire in Docker
Tools such as Query Monitor and Blackfire work inside Docker WordPress environments. Profiling inside the container gives a picture of performance under conditions close to production.
Migrating from MAMP or LocalWP to Docker
If you use MAMP, XAMPP or LocalWP, moving to Docker is simpler than it looks. The usual process is to export the databases, write Compose files that match your current setup and adopt the remaining practices step by step.
How to move a pilot project to Docker Compose
Start with a single pilot project. Write a compose.yaml that matches your current environment, including the PHP version, the database engine and the extensions you need. Once the pilot works, move the other projects.
How to import the database and wp-content
Export your databases with mysqldump and import them into the MariaDB container. Copy your WordPress files (especially wp-content) into the Docker volume layout. If the URL changes, for example to http://localhost:8080, run wp search-replace with WP-CLI and check that media and links work in the new environment.
Conclusion
Docker is no longer just for DevOps; it is a fundamental skill for WordPress developers in 2026. With containers you remove environment bugs, speed up onboarding and build more secure applications. The time spent learning Docker comes back in productivity and code quality.
Read more about my WordPress speed optimization services and how containerization feeds into the overall performance of your site.
Are you still fighting with local server configurations? It’s time to containerize your setup with Docker.






