How to Build Docker Compose Files (2026)
Docker Compose defines your entire application stack in a single YAML file. Instead of running docker commands for each container, docker compose up starts everything — your app, database, cache, and any other services — with one command. This guide covers the essential Docker Compose concepts for building reliable multi-container setups.
- Create docker-compose.
- Covers defining services.
- Covers ports and volumes.
- Covers environment variables and dependencies.
- Covers essential docker compose commands.
Defining Services
Each service in docker-compose.yml represents a container. The service name becomes the container's hostname on the Docker network. A typical web application has three services: the app itself, a database, and possibly a cache.
The image property specifies which Docker image to use. Use official images with version tags: postgres:15, redis:7-alpine, node:18-alpine. Avoid using 'latest' in production — pin specific versions for reproducibility.
Alpine-based images (-alpine suffix) are significantly smaller than standard images. node:18-alpine is about 120MB compared to 900MB+ for the standard image. Use Alpine unless you need specific packages that require a full Linux distribution.
Ports and Volumes
Port mapping follows the host:container pattern. ports: "3000:3000" maps port 3000 on your machine to port 3000 in the container. You can use different ports: "8080:3000" maps your port 8080 to the container port 3000.
-webkit-backdrop-filter alongside backdrop-filter for Safari support. Without the prefix, the effect is invisible to roughly 25% of mobile users.Volumes persist data between container restarts. Without volumes, database data is lost every time the container stops. Named volumes (pgdata:/var/lib/postgresql/data) are managed by Docker and survive container recreation.
Bind mounts (./src:/app/src) map host directories into the container. Use these for development so code changes are reflected instantly without rebuilding the image. Do not use bind mounts in production.
Environment Variables and Dependencies
Environment variables configure services without modifying images. Set database passwords, API keys, and feature flags through environment or env_file properties. Use env_file: .env to load from a file rather than listing them inline.
backdrop-filter inside a position: fixed element can cause severe scroll performance issues. Test thoroughly on real iOS devices.depends_on controls startup order. If your app needs the database, add depends_on: - db. Docker Compose starts the database before the app. Note: depends_on waits for the container to start, not for the service to be ready. Your app should implement connection retry logic.
Healthchecks verify a service is actually ready, not just running. Add healthcheck with a test command (like pg_isready for PostgreSQL). Combined with depends_on condition: service_healthy, this ensures services wait for true readiness.
Essential Docker Compose Commands
docker compose up -d starts all services in detached mode (background). Add --build to rebuild images before starting. This is your primary command for launching the stack.
docker compose down stops and removes all containers. Add -v to also remove volumes (caution: this deletes all data). Use docker compose stop to stop without removing containers.
docker compose logs -f follows the log output from all services. Add a service name to filter: docker compose logs -f web shows only the web service logs. Essential for debugging startup issues.
docker compose exec web sh opens a shell inside a running container. Use this to inspect files, run commands, or debug issues inside the container environment.