“It works on my machine” usually means the development environment is not described clearly enough. When every team member installs PHP, a database, a cache, and supporting tools differently, version and configuration problems eventually follow. Docker Compose turns those dependencies into configuration that can live with the source code and be recreated consistently.
What problem does Docker Compose solve?
A web application is rarely just source code. It may require an application server, MySQL or PostgreSQL, Redis, a fake mail service, and a queue worker. Compose describes these components as services together with the networks, volumes, and environment variables they need.
Instead of maintaining a long setup guide and hoping everyone follows it identically, the team can create the same service topology with one command. This is especially useful when onboarding a developer, replacing a computer, or reproducing a bug.
A small configuration that remains readable
services:
app:
build: .
ports:
- "8080:80"
volumes:
- ./:/var/www/html
depends_on:
db:
condition: service_healthy
db:
image: mysql:8.4
environment:
MYSQL_DATABASE: app
MYSQL_USER: app
MYSQL_PASSWORD: local_password
MYSQL_ROOT_PASSWORD: local_root_password
volumes:
- db_data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 5s
timeout: 3s
retries: 10
redis:
image: redis:7-alpine
volumes:
db_data:
depends_on expresses startup dependencies, while healthcheck tells Compose when the database is ready to accept connections. That is more reliable than merely waiting for a container process to start.
Understand the main components
| Component | Purpose | Practical note |
|---|---|---|
| Image | A read-only template used to create containers | Pin an intentional version instead of depending vaguely on latest |
| Container | A running process created from an image | It should be replaceable; do not use its internal filesystem for durable data |
| Volume | Persistent storage for data such as a database | Delete it only when local data is no longer needed |
| Network | Allows services to communicate by name | The app connects to db or redis, not localhost |
Environment variables and secrets
Compose can declare variables directly, interpolate them from the shell, or read environment files. A file containing real passwords should not be committed. Provide a safe .env.example and deliver staging or production secrets through the deployment platform's secret-management mechanism.
A containerized local environment is not a production architecture by itself. Production still needs deliberate secrets handling, backups, monitoring, upgrades, and recovery procedures.
The daily workflow
docker compose up -d --build
docker compose ps
docker compose logs -f app
docker compose exec app php artisan migrate
docker compose down
Add -v to docker compose down only when you intentionally want to remove volumes. For a local database containing useful test data, that flag can erase substantial setup work.
Improve the developer experience
- Create a development-specific
Dockerfilewhen the team needs a debugger or code-quality tools. - Use a bind mount for source code, but avoid dependency mounts that cause slow host filesystem I/O.
- Add healthchecks to databases and message brokers the application must wait for.
- Pin image versions intentionally and schedule upgrades.
- Put frequent commands in a script or Makefile so new contributors do not memorize long command lines.
Common problems
The app cannot connect to the database
Inside the Compose network, DB_HOST should be the service name, such as db, rather than 127.0.0.1. Also inspect the internal port, health status, and logs from both services.
Source changes do not appear
Check the volume path, working directory, and framework caches. A dependency or operating-system extension change requires an image rebuild; ordinary source changes only require a correct bind mount.
Data disappears after a restart
The database needs a named volume mounted at the image's correct data directory. Removing that volume or changing the Compose project name can also make the system start with a new data store.
Team adoption checklist
- A new developer can start the project from the README without verbal instructions.
- Image versions are explicit and have an upgrade plan.
- The repository contains no real passwords, tokens, or customer data.
- Databases and required dependencies have useful healthchecks.
- Migration, seed, test, and log commands are documented.
- The team has deleted containers and rebuilt them to confirm that required data persists.
Conclusion
Docker Compose does not eliminate every difference between local and production, but it gives the development team a clear environment contract. Start with the services the application truly needs, standardize daily commands, and test a clean rebuild.




No comments yet. Be the first to share your thoughts.