The project ships with a docker-compose.yml that provides all external services the application depends on. You don't need to install PostgreSQL, Redis, Memcached, RabbitMQ, MariaDB, MySQL, or Selenium locally — Docker handles all of them.
# Start all services in the background
docker-compose up -d
# Stop all services
docker-compose down
# View logs for a specific service
docker-compose logs -f redis
# Check status of all services
docker-compose ps
container_name: postgres_main_container
image: postgres:16-alpine
ports:
- '7003:5432'
environment:
- POSTGRES_USER=dbuser
- POSTGRES_PASSWORD=dbpass
- POSTGRES_DB=dbname
Connection string for .env:
DATABASE_URL="postgresql://dbuser:dbpassword@127.0.0.1:7003/dbname?serverVersion=16&charset=utf8"
PostgreSQL is the primary and fully supported database. All fixtures, triggers, and functions in the template project are written for PostgreSQL.
container_name: redis_main_container
image: redis:alpine
ports:
- '7002:6379'
Connection string for .env:
REDIS_CACHE_URL=redis://127.0.0.1:7002/0
Redis is the only required external service. The framework uses it for:
TEMPLATES_CACHE_ENABLED = true)DEV_MODE = false)rca()rp()rca()->pub()The application will not boot correctly without Redis. If Redis is unreachable, cache operations will throw and the request will fail.
container_name: memcached_main_container
image: memcached:alpine
ports:
- '7001:11211'
Connection string for .env:
MEMCACHED_SERVER=127.0.0.1
MEMCACHED_PORT=7001
Memcached is optional. The framework will use it when the Memcached PHP extension is loaded and these env vars are set. It is accessible via mca().
One important limitation: Memcached does not support key pattern deletion. Calling mca()->deleteByKeyPattern() will always throw UnsupportedPlatformException. Use mca()->clear() to flush everything, or use Redis for anything that needs pattern-based invalidation.
container_name: rabbitmq_main_container
image: rabbitmq:latest
ports:
- '7004:5672'
environment:
- RABBITMQ_DEFAULT_USER=admin
- RABBITMQ_DEFAULT_PASS=admin
Connection string for .env:
MESSENGER_TRANSPORT_DSN=amqp://admin:admin@127.0.0.1:7004/%2f
RabbitMQ is optional and only needed if you're using async message queues via QueueEnum. The default queue is configured in config/packages/messenger.yaml. See RabbitMQ for usage details.
container_name: mysql_main_container
image: mysql:latest
ports:
- '7005:3306'
environment:
- MYSQL_ROOT_PASSWORD=rootpassword
- MYSQL_DATABASE=dbname
- MYSQL_USER=dbuser
- MYSQL_PASSWORD=dbpassword
Connection string for .env:
DATABASE_URL="mysql://dbuser:dbpassword@127.0.0.1:7005/dbname?serverVersion=8&charset=utf8"
MySQL is provided as an additional database engine. Note that the fixture SQL files may use engine-specific syntax and will need to be adapted if you use a different engine than intended.
container_name: mariadb_main_container
image: mariadb:latest
ports:
- '7006:3306'
environment:
- MYSQL_ROOT_PASSWORD=rootpassword
- MYSQL_DATABASE=dbname
- MYSQL_USER=dbuser
- MYSQL_PASSWORD=dbpassword
Connection string for .env:
DATABASE_URL="mysql://dbuser:dbpassword@127.0.0.1:7006/dbname?serverVersion=10.11&charset=utf8"
MariaDB is provided as a second MySQL-protocol database engine alongside MySQL. Both can run simultaneously if your application uses multiple entity managers.
container_name: selenium_main_container
image: selenium/standalone-firefox:latest
ports:
- '4444:4444'
Selenium is included for browser-based acceptance testing via Codeception. It is only needed when running the Acceptance test suite. See Codeception for how to configure and run acceptance tests.
| Service | Internal port | Host port | Required |
|---|---|---|---|
| Memcached | 11211 | 7001 | No |
| Redis | 6379 | 7002 | Yes |
| PostgreSQL | 5432 | 7003 | No |
| RabbitMQ | 5672 | 7004 | No |
| MySQL | 3306 | 7005 | No |
| MariaDB | 3306 | 7006 | No |
| Selenium | 4444 | 4444 | No (acceptance tests only) |
Ports are intentionally set above 7000 to avoid conflicts with common local services running on their default ports.
You don't have to start all services. If you're not using RabbitMQ or Memcached, start only what you need:
# Only Redis and PostgreSQL
docker-compose up -d redis postgres
If you want to inspect the database with a GUI tool (TablePlus, DBeaver, pgAdmin, JetBrains IDE, etc.):
PostgreSQL
127.0.0.17003dbuserdbpassdbnameMySQL
127.0.0.17005dbuserdbpassworddbnameMariaDB
127.0.0.17006dbuserdbpassworddbnamedocker exec -it redis_php_sf_playground_container redis-cli
Useful commands for debugging the application cache:
# List all keys (use with caution in production)
KEYS *
# List keys by pattern
KEYS your-app-name:dev:cache:routes*
# Get a value
GET your-app-name:dev:cache:routes_list
# Delete all keys in current database
FLUSHDB
Note that all Redis keys are prefixed with SERVER_PREFIX:APP_ENV: — so if your SERVER_PREFIX is my-app and APP_ENV is dev, all keys will start with my-app:dev:.
By default the docker-compose.yml does not mount volumes for PostgreSQL or Redis, so data is lost when containers are stopped. For local development this is usually fine — fixtures can be reloaded quickly.
If you want data to persist, add volumes to docker-compose.yml:
postgres:
volumes:
- postgres_data:/var/lib/postgresql/data
redis:
volumes:
- redis_data:/data
volumes:
postgres_data:
redis_data:
Port already in use — if something is already running on port 7002 or 7003, either stop the conflicting service or change the host port in docker-compose.yml and update .env to match.
Redis connection refused — the most common boot failure. Verify Redis is running with docker-compose ps and that REDIS_CACHE_URL in .env points to the correct host and port.
PostgreSQL FATAL: password authentication failed — make sure DATABASE_URL credentials exactly match the POSTGRES_USER and POSTGRES_PASSWORD values in docker-compose.yml.
RabbitMQ connection refused on first start — RabbitMQ takes a few seconds to fully initialize after the container starts. If a connection error appears immediately after docker-compose up, wait a moment and retry.