This Docker setup provides multiple PHP and MySQL version combinations for testing DBDiff across different environments.
The Docker setup is configurable via environment variables. Copy .env.example to .env and customize:
cp .env.example .env
# Edit .env to customize ports, database credentials, timeouts, etc.
Key configuration options:
DB_PORT_MYSQL80, DB_PORT_MYSQL84, DB_PORT_MYSQL93 - MySQL database portsDB_PORT_POSTGRES16 - PostgreSQL 16 database port (default: 5432)PHPMYADMIN_PORT_MYSQL80, PHPMYADMIN_PORT_MYSQL84, PHPMYADMIN_PORT_MYSQL93 - PHPMyAdmin portsDB_ROOT_PASSWORD, DB_USER, DB_PASSWORD, DB_NAME - Database credentials (shared by MySQL and PostgreSQL)DATABASE_STARTUP_TIMEOUT, PHPUNIT_TEST_TIMEOUT - Timeout configurationsPodman is a daemonless, rootless, Docker-compatible container engine. All docker-compose commands work identically with podman-compose. Podman is a great alternative if you do not have Docker Desktop installed or prefer not to run a background daemon.
Ubuntu / Debian:
sudo apt-get install -y podman podman-compose
macOS (via Homebrew):
brew install podman podman-compose
podman machine init && podman machine start
Windows (via winget):
winget install RedHat.Podman
winget install RedHat.Podman-Desktop # optional GUI
Podman Desktop is a cross-platform GUI available at https://podman-desktop.io/ — it provides a Docker Desktop-like interface and can run the same compose files without any changes.
Simply substitute docker-compose for podman-compose in any command in this guide:
# Start PostgreSQL and run Postgres e2e tests
podman-compose up -d db-postgres16
podman-compose run --rm \
-e DB_HOST_POSTGRES=db-postgres16 \
cli-php83-postgres16 \
bash -c "scripts/run-tests.sh --postgres db-postgres16"
# Stop everything
podman-compose down
The start.sh and stop.sh scripts also support Podman automatically if docker-compose is not found:
# Prefer podman-compose when docker-compose is unavailable
COMPOSE_CMD=podman-compose ./start.sh 8.3 8.0
Podman runs containers as your own user by default. If port binding below 1024 fails, either:
.env (e.g. DB_PORT_MYSQL80=13306)sudo sysctl net.ipv4.ip_unprivileged_port_start=0 oncecli-php81-mysql80 - PHP 8.1 with MySQL 8.0cli-php81-mysql84 - PHP 8.1 with MySQL 8.4cli-php81-mysql93 - PHP 8.1 with MySQL 9.3cli-php81-mysql96 - PHP 8.1 with MySQL 9.6cli-php82-mysql80 - PHP 8.2 with MySQL 8.0cli-php82-mysql84 - PHP 8.2 with MySQL 8.4cli-php82-mysql93 - PHP 8.2 with MySQL 9.3cli-php82-mysql96 - PHP 8.2 with MySQL 9.6cli-php83-mysql80 - PHP 8.3 with MySQL 8.0cli-php83-mysql84 - PHP 8.3 with MySQL 8.4cli-php83-mysql93 - PHP 8.3 with MySQL 9.3cli-php84-mysql80 - PHP 8.4 with MySQL 8.0cli-php84-mysql84 - PHP 8.4 with MySQL 8.4cli-php84-mysql93 - PHP 8.4 with MySQL 9.3cli-php83-postgres16 - PHP 8.3 with PostgreSQL 16cli-php84-postgres16 - PHP 8.4 with PostgreSQL 16db-mysql80 - MySQL 8.0 (accessible on localhost:3306)db-mysql84 - MySQL 8.4 (accessible on localhost:3307)db-mysql93 - MySQL 9.3 (accessible on localhost:3308)db-postgres16 - PostgreSQL 16 (accessible on localhost:5432)phpmyadmin-mysql80 - PHPMyAdmin for MySQL 8.0 (http://localhost:8080)phpmyadmin-mysql84 - PHPMyAdmin for MySQL 8.4 (http://localhost:8081)phpmyadmin-mysql93 - PHPMyAdmin for MySQL 9.3 (http://localhost:8082)# Start MySQL 8.0 with PHPMyAdmin
docker-compose up -d db-mysql80 phpmyadmin-mysql80
# Start MySQL 8.4 with PHPMyAdmin
docker-compose up -d db-mysql84 phpmyadmin-mysql84
# Start MySQL 9.3 with PHPMyAdmin
docker-compose up -d db-mysql93 phpmyadmin-mysql93
# PHP 8.3 with MySQL 8.0
docker-compose run --rm cli-php83-mysql80 server1.php server2.php database1 database2
# PHP 8.4 with MySQL 8.4
docker-compose run --rm cli-php84-mysql84 server1.php server2.php database1 database2
# PHP 8.4 with MySQL 9.3
docker-compose run --rm cli-php84-mysql93 server1.php server2.php database1 database2
# Start the PostgreSQL service
docker-compose up -d db-postgres16
# Run a Postgres diff with PHP 8.3
docker-compose run --rm cli-php83-postgres16 \
bash -c "./dbdiff --driver=pgsql \
--server1=dbdiff:dbdiff@db-postgres16:5432 \
server1.mydb_staging:server1.mydb_production"
# Run tests with PHP 8.3 and MySQL 8.0
docker-compose run --rm cli-php83-mysql80 phpunit
# Run tests with PHP 8.4 and MySQL 8.4
docker-compose run --rm cli-php84-mysql84 phpunit
# Run PostgreSQL end-to-end tests (record baseline on first run)
docker-compose run --rm \
-e DB_HOST_POSTGRES=db-postgres16 \
cli-php83-postgres16 \
bash -c "DBDIFF_RECORD_MODE=true scripts/run-tests.sh --postgres db-postgres16"
# Run PostgreSQL end-to-end tests (compare against baseline)
docker-compose run --rm \
-e DB_HOST_POSTGRES=db-postgres16 \
cli-php83-postgres16 \
bash -c "scripts/run-tests.sh --postgres db-postgres16"
# Run SQLite end-to-end tests (no extra service needed)
docker-compose run --rm cli-php83-mysql80 bash -c "scripts/run-tests.sh --sqlite"
The start.sh script provides an easy way to test different PHP/MySQL combinations with automatic cleanup to save disk space.
# Test specific PHP/MySQL combination
./start.sh 8.3 8.0
# Test all combinations (sequentially)
./start.sh all all
# HIGH PERFORMANCE: Test all combinations in parallel
./start.sh all all --parallel
# RECORD MODE: Update expected test fixtures for all versions
./start.sh all all --record
# FAST RESTART: Skip heavy Docker cleanup for faster iterations
./start.sh 8.3 8.0 --fast
# Watch mode - single combination
./start.sh 8.3 8.0 --watch
# Interactive mode - select from menus
./start.sh
Advanced Flags:
--parallel): Spawns multiple background processes to test different MySQL major versions concurrently. This provides a ~3x speedup when running all all.--fast): Skips the aggressive deletion of Docker images and build caches between runs. Use this when iterating on code and the underlying environment/dependencies haven’t changed.--record): Tunnels the DBDIFF_RECORD_MODE environment variable into the test containers. This will cause tests to overwrite the expected fixtures in tests/expected/ with the actual current output.--watch):
--no-teardown): Containers remain active after script completion (works with both single and watch modes).Test Runner Modes:
--watch):
--no-teardown): Containers remain active after script completion (works with both single and watch modes)“All” Option Behavior:
Note: The start script automatically cleans up Docker containers, images, volumes, and build cache after each test to save disk space (unless –no-teardown is used).
Stop Script:
Use ./stop.sh to manually clean up all containers and resources, especially useful after using --no-teardown:
# Normal cleanup
./stop.sh
# Aggressive cleanup (removes everything)
./stop.sh --aggressive
# Show help
./stop.sh --help
# Start all databases and PHPMyAdmin instances
docker-compose up -d
# Or start specific combination
docker-compose up -d db-mysql80 phpmyadmin-mysql80 cli-php83-mysql80
# Stop all services
docker-compose down
# Remove all containers and images
docker-compose down --rmi all --volumes --remove-orphans
Default MySQL credentials (configurable via .env):
rootpass (DB_ROOT_PASSWORD)diff1 (DB_NAME)dbdiff (DB_USER)dbdiff (DB_PASSWORD)localhost:3306 (DB_PORT_MYSQL80)localhost:3307 (DB_PORT_MYSQL84)localhost:3308 (DB_PORT_MYSQL93)localhost:5432 (DB_PORT_POSTGRES16)The project uses GitHub Actions to ensure full compatibility across all supported versions on every pull request.
Matrix Grid:
pdo_sqlite)DBDiff is now built with deterministic SQL generation. This means:
ALTER statements within a table (columns, keys, constraints) are sorted by item name.INSERT, UPDATE, DELETE) are sorted by primary key.This ensures that test fixtures are stable across platforms and different database versions.
vendor/ folder.