Written by 5:38 pm For Developers, Getting Started with WordPress, How-To Guides Views: 0

How to Set Up a Local WordPress Development Environment in 2026 (DDEV vs Local vs Docker)

Compare DDEV, Local by Flywheel, Lando, and raw Docker Compose for setting up a local WordPress development environment in 2026. Concrete setup commands, PHP and MySQL version switching, Xdebug, Mailpit, multisite, and custom domains for each tool.

DDEV vs Local vs Docker Compose comparison for local WordPress development in 2026

Setting up a local WordPress development environment used to mean downloading XAMPP, fighting PHP version conflicts, and praying your MySQL port wasn’t already in use. In 2026, you have four solid options that are actually pleasant to use: DDEV, Local by Flywheel, Lando, and raw Docker Compose. Each one takes a different approach to the same problem. This guide walks through all four with concrete commands, so you can pick the right one for your workflow rather than just the most popular one.

Why Local Development Matters (and Why the Old Way Was Painful)

Before comparing tools, it is worth understanding what you are actually solving. A local environment lets you build, break, and fix WordPress without touching a live server. You can experiment with plugins, test theme changes, debug PHP errors without any user seeing them, and commit your work to Git before it ever reaches production.

The old XAMPP/WAMP approach worked but required manual configuration every time your project changed. Need PHP 8.2 for one project and PHP 8.0 for another? Good luck managing that with a global XAMPP install. Need Xdebug? That meant editing php.ini files manually. Mailpit for catching outgoing email? Not a built-in concept.

Modern local development tools solve all of this with container-based isolation. Each project gets its own PHP version, MySQL version, web server config, and environment variables. Switching projects means switching directories, not reconfiguring your entire machine.

The Four Tools at a Glance

Here is a quick summary before we go deep on each one:

  • DDEV – Docker-based, command-line focused, excellent for teams and CI/CD pipelines, strong plugin ecosystem
  • Local by Flywheel – Desktop GUI, easiest onboarding, built for WordPress specifically, free tier available
  • Lando – Docker-based, highly flexible, config-file driven, handles non-WordPress stacks too
  • Raw Docker Compose – Full control, steeper learning curve, best for custom setups, no abstraction layer

DDEV: The Developer’s Developer Tool

What DDEV Is

DDEV is an open-source, container-based local development environment built on top of Docker. It was originally designed for Drupal and TYPO3 teams but has grown to be one of the most popular WordPress dev tools among experienced developers. It uses a YAML config file per project, which makes it easy to share environments across teams and check configs into version control.

Installing DDEV

On macOS with Homebrew:

brew install ddev/ddev/ddev

On Ubuntu/Debian Linux:

curl -fsSL https://ddev.com/install.sh | bash

On Windows with WSL2, DDEV runs inside your Linux subsystem. Install WSL2 first, then use the Linux install script above. You will also need Docker Desktop running in the background (or Orbstack on Mac if you prefer a lighter-weight Docker runtime).

Creating a WordPress Project with DDEV

mkdir my-wp-site && cd my-wp-site
ddev config --project-type=wordpress --docroot=. --project-name=my-wp-site
ddev start
ddev wp core download
ddev wp core install \
  --url=https://my-wp-site.ddev.site \
  --title="My WP Site" \
  --admin_user=admin \
  --admin_password=admin \
  [email protected]

DDEV automatically provisions an SSL certificate for the .ddev.site domain, so your local site runs on HTTPS out of the box. No hosts file editing required.

Switching PHP Versions in DDEV

ddev config --php-version 8.2
ddev restart

Supported versions as of 2026: PHP 7.4, 8.0, 8.1, 8.2, 8.3. The version is stored in .ddev/config.yaml, so it travels with your project repo.

Switching MySQL/MariaDB Versions

ddev config --database mysql:8.0
ddev restart

Or use MariaDB: ddev config --database mariadb:10.6. Changing the database version on an existing project requires exporting the database first: ddev export-db --file=/tmp/backup.sql, then restart, then import.

Enabling Xdebug in DDEV

ddev xdebug on

That is it. DDEV handles the php.ini configuration automatically. To use it in VS Code, install the PHP Debug extension and add a launch config pointing to port 9003. To turn Xdebug off when you do not need it (it slows page loads):

ddev xdebug off

Mailpit in DDEV

DDEV ships with Mailpit pre-configured. Every email WordPress tries to send gets caught and shown in the Mailpit web UI. Access it at:

ddev launch -m

This opens the Mailpit inbox in your browser. No extra plugin or configuration needed.

WordPress Multisite with DDEV

ddev wp core multisite-install \
  --url=https://my-wp-site.ddev.site \
  --title="My Network" \
  --admin_user=admin \
  --admin_password=admin \
  [email protected]

# For subdomain multisite, update .ddev/config.yaml:
# additional_fqdns: ["*.my-wp-site.ddev.site"]
ddev restart

Custom Domains in DDEV

Add custom domains by editing .ddev/config.yaml:

additional_fqdns:
  - mysite.local
  - store.mysite.local

Then run ddev restart. DDEV updates your hosts file automatically.

When to Choose DDEV

DDEV is the best choice when you work in a team and need reproducible environments. The config file commits to Git, and a new team member runs ddev start to get an identical setup. It is also the best option if you are building a CI pipeline, since DDEV works headlessly in GitHub Actions and similar environments. The trade-off is that you need to be comfortable with the command line.

Local by Flywheel: The Friendliest Option

What Local Is

Local (formerly Local by Flywheel) is a desktop application built specifically for WordPress development. It has a graphical interface, one-click site creation, and built-in tools for common workflows. WP Engine owns it, but it works with any WordPress host. The free version covers everything most developers need.

Installing Local

Download the installer from localwp.com for macOS, Windows, or Linux. Run the installer and open the application. No terminal required for basic setup.

Creating a WordPress Site in Local

Click the “+” button in the bottom left corner. Give your site a name, choose your environment (PHP version, web server, MySQL version), and click “Create Site.” Local downloads the WordPress files, configures the database, and sets up the site automatically. The whole process takes about 60 seconds on a fast connection.

PHP and MySQL Version Switching

Right-click any site and choose “Change PHP version” or “Change MySQL version.” Local will restart the environment with the new versions. This is the easiest version-switching experience of any tool on this list.

Xdebug in Local

Click the three-dot menu next to your site, then “Enable Xdebug.” Local configures everything automatically. It even shows a pop-up with the launch config you need in VS Code or PhpStorm. Disable it the same way when you are done debugging.

Mail Catching in Local

Local includes Mailpit (previously MailHog) built in. Open the Local app, click your site, and look for the “Mailpit” tab or the “Open Mailpit” button. All outgoing email from that WordPress install goes there automatically.

Multisite in Local

Local has a dedicated multisite option in the site creation wizard. Choose “Multisite” and pick between subdomain and subdirectory. Local handles the configuration and hosts file changes for you. Subdomain multisite requires the Pro version for wildcard domain support.

Performance Notes

Local runs on a technology called Lightning Services on macOS, which bypasses Docker entirely and runs PHP and MySQL directly. This makes it significantly faster than Docker-based tools on Mac. On Windows, Local uses Docker under the hood, so performance is similar to DDEV and Lando.

When to Choose Local

Local is the best choice for solo developers, designers, and anyone who prefers a GUI over the terminal. It is also the fastest to get started with, which makes it a great recommendation for clients or team members who are not primarily developers. The main limitation is that Local configs are not easily shareable via Git, so team environments can drift over time.

Lando: The Flexible All-Rounder

What Lando Is

Lando is a Docker-based local development tool with a focus on flexibility. It supports WordPress, Drupal, Laravel, Symfony, Node, and many other stacks from the same tool. Configuration lives in a .lando.yml file at the project root. It sits at a similar abstraction level to DDEV but with different defaults and a larger service ecosystem.

Installing Lando

Download the latest installer from docs.lando.dev. Lando requires Docker Desktop (or Orbstack on Mac). On macOS:

brew install --cask lando

Creating a WordPress Site with Lando

Create a .lando.yml in your project directory:

name: my-wp-site
recipe: wordpress
config:
  webroot: .
  php: '8.2'
  database: mysql:8.0
  xdebug: true

Then run:

lando start
lando wp core download
lando wp core install \
  --url=http://my-wp-site.lndo.site \
  --title="My WP Site" \
  --admin_user=admin \
  --admin_password=admin \
  [email protected]

Lando automatically creates a .lndo.site domain with a self-signed certificate.

PHP and MySQL Version Switching in Lando

Edit .lando.yml and change the version numbers, then run lando rebuild. This is slightly slower than DDEV’s restart because Lando rebuilds containers from scratch, but it is just as predictable.

Mailpit in Lando

Lando does not include Mailpit by default, but adding it takes a few lines in .lando.yml:

services:
  mailpit:
    type: lando
    services:
      image: axllent/mailpit
      ports:
        - "8025:8025"
        - "1025:1025"

Then add an SMTP plugin in WordPress pointing to mailpit:1025.

Custom Domains in Lando

proxy:
  appserver:
    - mysite.lndo.site
    - store.mysite.lndo.site

Add those lines to .lando.yml and run lando rebuild.

When to Choose Lando

Lando is the best choice when your team works with multiple platforms. If you build WordPress sites but also maintain a Laravel API and a Node frontend, Lando handles all three with the same CLI pattern. It is also a good choice if you need more control over the Docker service configuration than DDEV exposes by default.

Raw Docker Compose: Maximum Control

What You Get (and What You Give Up)

Running WordPress in raw Docker Compose means no abstraction layer, no magic commands. You write the docker-compose.yml yourself, configure PHP via a custom Dockerfile if needed, and manage everything manually. This is more work upfront but gives you complete control over every layer.

A Production-Grade docker-compose.yml for WordPress

version: '3.8'

services:
  db:
    image: mysql:8.0
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: rootpass
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wpuser
      MYSQL_PASSWORD: wppass
    volumes:
      - db_data:/var/lib/mysql

  wordpress:
    image: wordpress:php8.2-apache
    restart: unless-stopped
    depends_on:
      - db
    ports:
      - "8080:80"
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: wpuser
      WORDPRESS_DB_PASSWORD: wppass
      WORDPRESS_DB_NAME: wordpress
      WORDPRESS_DEBUG: 'true'
    volumes:
      - ./wp-content:/var/www/html/wp-content
      - ./php.ini:/usr/local/etc/php/conf.d/custom.ini

  mailpit:
    image: axllent/mailpit
    ports:
      - "8025:8025"
      - "1025:1025"

volumes:
  db_data:

Start the stack with docker compose up -d. Access WordPress at http://localhost:8080 and Mailpit at http://localhost:8025.

Adding Xdebug to Docker Compose

Create a php.ini file alongside your docker-compose.yml:

[xdebug]
zend_extension=xdebug
xdebug.mode=debug
xdebug.start_with_request=yes
xdebug.client_host=host.docker.internal
xdebug.client_port=9003

The volume mount in the docker-compose.yml above loads this file automatically. Restart the stack after creating the file.

Switching PHP Versions in Docker Compose

Change the image tag in the wordpress: service. For PHP 8.3:

image: wordpress:php8.3-apache

Then run docker compose up -d --force-recreate wordpress.

Custom Domains with Docker Compose

Docker Compose does not manage your hosts file. You need to add entries manually:

sudo sh -c 'echo "127.0.0.1 mysite.local" >> /etc/hosts'

For SSL, you can use a local reverse proxy like Traefik or Caddy. This adds complexity but gives you proper HTTPS locally.

When to Choose Raw Docker Compose

Choose Docker Compose when you need to match a production environment exactly, when you are building a custom hosting platform, or when the abstraction layers in DDEV and Lando are actively getting in your way. It is also the right choice for learning Docker itself, since you see every layer exposed. For pure WordPress development, it is usually more work than it is worth compared to DDEV or Local.

Head-to-Head Comparison

Feature DDEV Local Lando Docker Compose
PHP version switching One command GUI click Edit YAML + rebuild Edit YAML + recreate
Xdebug setup One command GUI toggle Config flag Manual php.ini
Mailpit included Yes Yes Manual service Manual service
Team-shareable config Yes (.yaml in Git) Limited Yes (.lando.yml) Yes (docker-compose.yml)
Multisite support Via WP-CLI GUI wizard Via WP-CLI Manual
macOS performance Good Excellent Good Variable
Non-WordPress stacks Partial No Yes Yes
SSL out of the box Yes Yes Self-signed Manual
Learning curve Medium Low Medium High

Performance Testing: Which Is Fastest?

On an M2 MacBook Pro, a fresh WordPress install with no plugins loads in roughly these times using curl -o /dev/null -s -w "%{time_total}":

  • Local (Lightning Services): 40-80ms for a cached page load
  • DDEV with Mutagen sync: 60-120ms
  • Lando: 80-150ms
  • Raw Docker Compose: 100-200ms (highly dependent on volume mount strategy)

The gap widens when you have large themes and many plugins. File system access through Docker volumes is the main bottleneck on macOS. DDEV uses Mutagen for file synchronization, which dramatically improves this. Local bypasses the Docker file system entirely on Mac, which is why it is the fastest.

On Linux, Docker uses native file system access, so all four tools perform similarly well.

Setting Up WP-CLI in Each Tool

WP-CLI is how you manage WordPress from the terminal: install plugins, run database operations, manage users, and more. Here is how to run WP-CLI commands in each tool:

# DDEV
ddev wp plugin install woocommerce --activate

# Local
# Use the "Open Site Shell" button in the GUI, then:
wp plugin install woocommerce --activate

# Lando
lando wp plugin install woocommerce --activate

# Raw Docker Compose
docker compose exec wordpress wp plugin install woocommerce --activate --allow-root

DDEV and Lando wrap WP-CLI as a built-in command. Local gives you shell access to the container. Docker Compose requires you to exec into the container each time unless you alias it.

If you are building or testing plugins, you will likely spend significant time running WP-CLI commands. Before you push updates to a live site, it helps to read the guide on safely updating WordPress plugins without breaking your live site so you understand the staging-to-production workflow.

Managing Multiple Projects

One of the biggest advantages of any Docker-based local tool is running multiple WordPress installs simultaneously without port conflicts.

With DDEV, each project gets its own subdomain under .ddev.site. You can have client-a.ddev.site, client-b.ddev.site, and my-plugin.ddev.site all running at the same time. Start and stop individual projects:

ddev start        # start current project
ddev stop         # stop current project
ddev stop --all   # stop everything

With Local, each site is listed in the GUI. Toggle sites on and off with a click. Local handles port management automatically.

With Lando, use lando start and lando stop per project directory. Unlike DDEV, all running Lando projects share some Docker resources, so running five at once uses more memory than DDEV’s approach.

Database Management

All four tools give you access to the WordPress database. Here are the options for each:

# DDEV: open Adminer in browser
ddev launch --phpmyadmin
# or use the DDEV database service directly:
ddev mysql

# Lando
lando phpmyadmin  # opens phpMyAdmin
# or direct access:
lando db

# Local: built-in Adminer in the GUI
# Click "Adminer" tab in the site details

# Docker Compose: connect your MySQL client to localhost:3306
# Or run phpMyAdmin as a service by adding it to docker-compose.yml

Exporting and Sharing Environments

When you want to pass a project to a colleague or deploy to staging, exporting the database and files is a standard step. Here are the key commands:

# DDEV: export database
ddev export-db --file=db-export.sql.gz

# Import on another machine (after ddev start):
ddev import-db --file=db-export.sql.gz

# Lando:
lando db-export db-export.sql.gz
lando db-import db-export.sql.gz

For Docker Compose:

docker compose exec db mysqldump -u wpuser -pwppass wordpress > db-export.sql
docker compose exec -T db mysql -u wpuser -pwppass wordpress < db-export.sql

When something goes wrong after importing or updating your environment, knowing how to recover is just as important as the setup. The guide on what to do when a WordPress update breaks your site covers the recovery steps you need for both local and live environments.

Which Tool Should You Choose?

Here is a straightforward decision tree:

Choose Local if: you are new to local development, you prefer GUIs over the terminal, you are working solo, or raw macOS speed matters to you. The onboarding is the smoothest and you can get a WordPress site running in under two minutes.

Choose DDEV if: you work in a team and need reproducible environments, you want your dev setup committed to Git alongside your code, or you use WP-CLI heavily. DDEV's one-command Xdebug toggle and built-in Mailpit make it the most complete CLI tool in this group.

Choose Lando if: your team works with multiple technology stacks, you need finer control over Docker service configuration than DDEV exposes, or you are already using Lando for non-WordPress projects.

Choose Docker Compose if: you need an exact mirror of a production Docker environment, you are building a custom platform, or you want to learn how the underlying container infrastructure works without any abstraction on top.

For most WordPress developers in 2026, the choice comes down to DDEV (CLI-first, team-friendly) versus Local (GUI-first, solo-friendly). Both are free, both are actively maintained, and both handle every major WordPress use case. Start with Local if you are not sure. You can always migrate to DDEV later when your workflow grows more complex.

Advanced Tips: Making Your Local Environment Work Like a Pro Setup

Use object caching locally

Redis and Memcached work locally just like they do on production servers. DDEV includes Redis as an optional service:

ddev get ddev/ddev-redis
ddev restart

Then install the Redis Object Cache plugin in WordPress and activate drop-in persistence. Testing your plugin or theme against a cached environment locally catches bugs that only appear on production, especially around cache invalidation and transients.

Mirror your production PHP config

Different PHP settings between local and production are a common source of "works on my machine" bugs. Copy your production php.ini values into a local override file. In DDEV, this goes in .ddev/php/my-php.ini. Common values to match:

  • memory_limit: set to match your host (128M, 256M, 512M)
  • max_execution_time: 30 or 60 depending on your host
  • upload_max_filesize and post_max_size: match your host's limits
  • error_reporting: set to E_ALL locally to catch notices and warnings

Use Git for your wp-content directory only

Never put the entire WordPress core into version control. Your Git repo should track only what you own: wp-content/themes/your-theme/, wp-content/plugins/your-plugin/, and a composer.json or package.json for dependencies. A standard .gitignore for WordPress projects excludes:

/wp-admin/
/wp-includes/
/wp-content/uploads/
/wp-config.php
*.log

This keeps your repository small and avoids committing sensitive database credentials or user-generated content.

Set up automated database snapshots

Before testing a risky plugin update or data migration locally, snapshot your database. In DDEV:

ddev snapshot create --name=before-update
# ... run your tests ...
ddev snapshot restore before-update

This is faster than a full export/import cycle and gives you a quick rollback path during development.

Environment variables and wp-config.php

Avoid hard-coding credentials in wp-config.php. All four tools support environment variables that you can read in PHP. In DDEV, add to .ddev/config.yaml:

web_environment:
  - STRIPE_SECRET_KEY=sk_test_abc123
  - SENDGRID_API_KEY=SG.xyz

Then in wp-config.php:

define('STRIPE_SECRET_KEY', getenv('STRIPE_SECRET_KEY'));

This pattern works identically in local, staging, and production environments when each has the appropriate env vars set.

Getting Your Workflow Production-Ready

A local environment is only useful if it connects to a reliable deployment process. Once you are comfortable with your chosen tool, the next step is establishing a staging-to-production workflow: test locally, push to a staging URL, review, then deploy. All four tools make this easier because your database exports and file syncs are standardized.

Whatever tool you pick, keep Xdebug off by default and only enable it when you are actively debugging. Keep Mailpit running so you catch all outgoing email during development. Use WP-CLI for anything repetitive. And keep your wp-content directory under version control, separate from WordPress core files.

A well-configured local environment is the foundation that makes everything else in WordPress development faster, safer, and less stressful. It is the single best investment you can make in your workflow, and with any of the four tools in this guide, you can have a fully working WordPress stack running in under five minutes.

Visited 1 times, 1 visit(s) today

Last modified: May 8, 2026

Close