TL;DR
A Docker Compose generator lets you visually build docker-compose.yml files without writing YAML by hand. This guide covers every aspect of Docker Compose: file structure, services, networks, volumes, environment variables, health checks, dependency management, profiles, override files, common multi-service patterns, and production best practices. Use our free Docker Compose Generator to scaffold your next project in seconds.
Key Takeaways
- Docker Compose defines multi-container applications in a single YAML file with services, networks, and volumes.
- The Compose V2 CLI (
docker compose) replaces the legacy Python-baseddocker-composetool. - Use
depends_onwithcondition: service_healthyto wait for real readiness, not just container start. - Profiles let you selectively enable services like debug tools or monitoring without separate Compose files.
- Override files (
docker-compose.override.yml) keep your base config clean while layering environment-specific settings. - For production: pin image tags, set restart policies, limit resources, enable health checks, and externalize secrets.
- An online Docker Compose generator eliminates YAML indentation errors and scaffolds projects in seconds.
Build Your docker-compose.yml Online
Skip the YAML headaches. Visually configure services, volumes, and networks then copy the result.
Open Docker Compose Generator1. What Is Docker Compose?
Docker Compose is a tool for defining and running multi-container Docker applications. Instead of managing individual docker run commands with lengthy flags, you describe your entire application stack in a declarative YAML file called docker-compose.yml. A single commandโdocker compose upโcreates and starts all the services, networks, and volumes your application needs.
Compose is used everywhere: local development environments, CI/CD pipelines, staging servers, and even single-host production deployments. It bridges the gap between running one container at a time and orchestrating dozens of services with Kubernetes.
Why Use an Online Docker Compose Generator?
YAML is notoriously sensitive to indentation. A single misplaced space can break your entire stack. A Docker Compose generator provides a visual interface where you select services, configure ports, volumes, and environment variables, then export a valid, well-formatted docker-compose.yml file. Benefits include:
- Zero YAML syntax errorsโthe generator handles formatting automatically.
- Pre-built templates for popular services like PostgreSQL, MySQL, Redis, Nginx, and more.
- Real-time validation of port mappings, volume mounts, and network configurations.
- Quick scaffolding for new projectsโgo from idea to running stack in minutes.
- Learning aidโsee how visual choices translate to YAML syntax.
2. Docker Compose File Structure
Every docker-compose.yml file is built around four top-level keys. Understanding this structure is essential before using any generator or writing Compose files by hand.
# docker-compose.yml โ top-level structure
services: # Define your application containers
web:
image: nginx:alpine
api:
build: ./api
db:
image: postgres:16
volumes: # Declare persistent storage
db-data:
networks: # Define custom networks
frontend:
backend:
configs: # (Optional) External configuration files
nginx-conf:
file: ./nginx.confversion field at the top of the file is no longer required since Docker Compose V2. Compose automatically detects and merges features from all schema versions.Top-Level Keys Explained
| Key | Purpose | Required |
|---|---|---|
services | Defines each container (image, build, ports, env, volumes, etc.) | Yes |
volumes | Declares named volumes for persistent data | No |
networks | Creates custom networks for service isolation | No |
configs | Mounts configuration files into containers | No |
secrets | Manages sensitive data like passwords and API keys | No |
3. Defining Services
Services are the heart of any Compose file. Each service becomes one or more running containers. Here is a complete reference of the most important service options.
Image vs Build
You can either pull a pre-built image or build from a Dockerfile:
services:
# Pull from Docker Hub
redis:
image: redis:7-alpine
# Build from local Dockerfile
api:
build: ./api
# Build with advanced options
frontend:
build:
context: ./frontend
dockerfile: Dockerfile.prod
args:
NODE_ENV: production
NEXT_PUBLIC_API_URL: https://api.example.com
target: runner # Multi-stage build target
cache_from:
- myapp-frontend:cachePort Mapping
Expose container ports to the host with the ports key. The format is HOST:CONTAINER:
services:
web:
image: nginx:alpine
ports:
- "80:80" # HTTP
- "443:443" # HTTPS
- "127.0.0.1:8080:80" # Bind to localhost only
- "3000-3005:3000-3005" # Port range
api:
build: ./api
ports:
- "3000:3000"
expose:
- "9229" # Expose to other services only (debug port)0.0.0.0 in production for internal services. Use 127.0.0.1:PORT:PORT or rely on Docker networks for inter-service communication instead.Restart Policies
Control what happens when a container exits:
| Policy | Behavior | Best For |
|---|---|---|
no | Never restart (default) | One-off tasks, debugging |
always | Always restart, even on clean exit | Critical services that must always run |
unless-stopped | Restart unless manually stopped | Most production services |
on-failure | Restart only on non-zero exit code | Workers, batch jobs |
services:
api:
image: myapp:latest
restart: unless-stopped
worker:
image: myapp:latest
command: ["node", "worker.js"]
restart: on-failure4. Environment Variables
Environment variables are the primary way to configure containers. Docker Compose supports multiple approaches, each suited to different use cases.
Inline Environment
services:
api:
image: myapp:latest
environment:
NODE_ENV: production
DB_HOST: db
DB_PORT: "5432"
DB_NAME: myapp
LOG_LEVEL: infoUsing env_file
services:
api:
image: myapp:latest
env_file:
- .env # Loaded first
- .env.production # Overrides values from .env
# .env file format:
# DB_HOST=localhost
# DB_PORT=5432
# DB_PASSWORD=secret123Variable Substitution
Compose reads a .env file in the project root automatically and substitutes variables in the YAML:
# .env
POSTGRES_VERSION=16
APP_PORT=3000
# docker-compose.yml
services:
db:
image: postgres:${POSTGRES_VERSION}
api:
ports:
- "${APP_PORT:-3000}:3000" # Default to 3000 if not setdocker-compose.yml. Use env_file for non-sensitive config and Docker secrets or a vault for passwords, API keys, and tokens.5. Volumes: Persistent Data
Volumes persist data beyond the lifecycle of a container. Without them, all data inside a container is lost when it stops or is recreated.
Named Volumes vs Bind Mounts
services:
db:
image: postgres:16
volumes:
# Named volume โ managed by Docker, persists across restarts
- db-data:/var/lib/postgresql/data
# Bind mount โ maps a host directory into the container
- ./init-scripts:/docker-entrypoint-initdb.d
# Read-only bind mount
- ./pg-config/postgresql.conf:/etc/postgresql/postgresql.conf:ro
volumes:
db-data: # Declaration required for named volumes
driver: local| Feature | Named Volume | Bind Mount |
|---|---|---|
| Managed by | Docker Engine | Host filesystem |
| Portability | High (works on any host) | Low (path must exist) |
| Performance | Better on macOS/Windows | Native on Linux |
| Use case | Database storage, persistent data | Development hot-reload, config files |
Survives docker compose down | Yes | Yes (data stays on host) |
Removed by down -v | Yes | No |
6. Networks: Service Communication
By default, Docker Compose creates a single network for all services. Services can reach each other using their service name as a hostname. Custom networks let you isolate groups of services for security or clarity.
services:
web:
image: nginx:alpine
networks:
- frontend
api:
build: ./api
networks:
- frontend # Can talk to web
- backend # Can talk to db
db:
image: postgres:16
networks:
- backend # Isolated from web
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true # No external accessinternal: true on backend networks to prevent containers from accessing the internet. This is a simple but effective security measure for database and cache services.7. Health Checks
Health checks let Docker monitor whether a service is actually ready to accept traffic, not just running. They are critical for reliable dependency management with depends_on.
services:
db:
image: postgres:16
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s # Check every 10 seconds
timeout: 5s # Fail if no response in 5s
retries: 5 # Mark unhealthy after 5 failures
start_period: 30s # Grace period on startup
redis:
image: redis:7-alpine
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 3
api:
build: ./api
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:3000/health || exit 1"]
interval: 15s
timeout: 5s
retries: 3
start_period: 10sCommon Health Check Commands
| Service | Health Check Command |
|---|---|
| PostgreSQL | pg_isready -U postgres |
| MySQL | mysqladmin ping -h localhost |
| Redis | redis-cli ping |
| MongoDB | mongosh --eval "db.adminCommand('ping')" |
| Elasticsearch | curl -f http://localhost:9200/_cluster/health |
| HTTP API | curl -f http://localhost:PORT/health || exit 1 |
8. Dependency Management with depends_on
The depends_on key controls the order in which services start. The simple list form only guarantees start order, not readiness. For true readiness, combine it with health checks.
Simple Form (Start Order Only)
services:
api:
build: ./api
depends_on:
- db
- redis
db:
image: postgres:16
redis:
image: redis:7-alpineLong Form with Health Conditions
services:
api:
build: ./api
depends_on:
db:
condition: service_healthy # Wait for DB healthcheck to pass
restart: true # Restart api if db restarts
redis:
condition: service_healthy
migrations:
condition: service_completed_successfully # Wait for one-off task
db:
image: postgres:16
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
retries: 10
redis:
image: redis:7-alpine
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
retries: 5
migrations:
build: ./api
command: ["npm", "run", "migrate"]
depends_on:
db:
condition: service_healthycondition: service_healthy syntax requires that the dependency service has a healthcheck defined. Without it, Compose will error with a "has no healthcheck" message.9. Common Docker Compose Patterns
Below are production-tested patterns you can generate with our tool or adapt for your own projects.
Pattern 1: Web + API + Database + Cache
The most common full-stack setup: a reverse proxy, an application server, a database, and a cache layer.
services:
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/certs:/etc/nginx/certs:ro
depends_on:
api:
condition: service_healthy
restart: unless-stopped
networks:
- frontend
api:
build:
context: ./api
target: production
environment:
NODE_ENV: production
DATABASE_URL: postgres://app:secret@db:5432/myapp
REDIS_URL: redis://redis:6379
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:3000/health || exit 1"]
interval: 10s
timeout: 5s
retries: 3
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
restart: unless-stopped
networks:
- frontend
- backend
db:
image: postgres:16-alpine
environment:
POSTGRES_DB: myapp
POSTGRES_USER: app
POSTGRES_PASSWORD: secret
volumes:
- db-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app -d myapp"]
interval: 10s
retries: 5
restart: unless-stopped
networks:
- backend
redis:
image: redis:7-alpine
command: redis-server --maxmemory 256mb --maxmemory-policy allkeys-lru
volumes:
- redis-data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
retries: 3
restart: unless-stopped
networks:
- backend
volumes:
db-data:
redis-data:
networks:
frontend:
backend:
internal: truePattern 2: Full-Stack JavaScript (Next.js + PostgreSQL + Redis)
services:
app:
build:
context: .
dockerfile: Dockerfile
ports:
- "3000:3000"
environment:
DATABASE_URL: postgres://dev:devpass@db:5432/nextapp
REDIS_URL: redis://redis:6379
NEXTAUTH_SECRET: your-secret-here
NEXTAUTH_URL: http://localhost:3000
volumes:
- .:/app # Hot reload in development
- /app/node_modules # Exclude node_modules from bind mount
- /app/.next # Exclude .next build cache
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
restart: unless-stopped
db:
image: postgres:16-alpine
environment:
POSTGRES_DB: nextapp
POSTGRES_USER: dev
POSTGRES_PASSWORD: devpass
ports:
- "5432:5432"
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U dev"]
interval: 5s
retries: 10
redis:
image: redis:7-alpine
ports:
- "6379:6379"
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
retries: 5
volumes:
pgdata:Pattern 3: WordPress + MySQL + phpMyAdmin
services:
wordpress:
image: wordpress:6-apache
ports:
- "8080:80"
environment:
WORDPRESS_DB_HOST: mysql
WORDPRESS_DB_USER: wp
WORDPRESS_DB_PASSWORD: wppass
WORDPRESS_DB_NAME: wordpress
volumes:
- wp-content:/var/www/html/wp-content
depends_on:
mysql:
condition: service_healthy
restart: unless-stopped
mysql:
image: mysql:8
environment:
MYSQL_DATABASE: wordpress
MYSQL_USER: wp
MYSQL_PASSWORD: wppass
MYSQL_ROOT_PASSWORD: rootpass
volumes:
- mysql-data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
retries: 5
restart: unless-stopped
phpmyadmin:
image: phpmyadmin:latest
ports:
- "8081:80"
environment:
PMA_HOST: mysql
PMA_USER: root
PMA_PASSWORD: rootpass
depends_on:
mysql:
condition: service_healthy
volumes:
wp-content:
mysql-data:10. Compose File Versions: V2 vs V3
Docker Compose historically used a version field to specify the file format. Understanding the differences helps when reading older Compose files or migrating legacy projects.
| Feature | Version 2.x | Version 3.x | Current (no version field) |
|---|---|---|---|
| Target | Docker Engine (single host) | Docker Swarm | Both |
depends_on conditions | Supported | Not supported | Supported |
| Resource limits | Under service key | Under deploy | Both locations |
version field | Required | Required | Optional (deprecated) |
| CLI tool | docker-compose (Python) | docker-compose | docker compose (Go) |
version field entirely and use the latest docker compose (V2 CLI). This gives you access to all features from both legacy version schemas.11. Docker Compose Profiles
Profiles let you include optional services that only start when explicitly activated. This keeps your default docker compose up lean while allowing access to debug tools, monitoring, or testing services on demand.
services:
api:
build: ./api
# No profiles = always starts
db:
image: postgres:16
# No profiles = always starts
# Only starts with --profile debug
pgadmin:
image: dpage/pgadmin4
ports:
- "5050:80"
environment:
PGADMIN_DEFAULT_EMAIL: admin@local.dev
PGADMIN_DEFAULT_PASSWORD: admin
profiles:
- debug
# Only starts with --profile monitoring
prometheus:
image: prom/prometheus
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
profiles:
- monitoring
grafana:
image: grafana/grafana
ports:
- "3001:3000"
profiles:
- monitoring
# Only starts with --profile test
test-runner:
build: ./api
command: ["npm", "test"]
profiles:
- test# Start only core services
docker compose up -d
# Start core + debug tools
docker compose --profile debug up -d
# Start core + monitoring
docker compose --profile monitoring up -d
# Start everything
docker compose --profile debug --profile monitoring up -d
# Or use environment variable
COMPOSE_PROFILES=debug,monitoring docker compose up -d12. Extending with Override Files
Docker Compose automatically merges docker-compose.yml with docker-compose.override.yml if both exist. This pattern is the standard way to separate base configuration from environment-specific overrides.
Base File (docker-compose.yml)
# docker-compose.yml โ shared base config
services:
api:
build: ./api
depends_on:
db:
condition: service_healthy
db:
image: postgres:16
volumes:
- db-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
retries: 5
volumes:
db-data:Development Override (docker-compose.override.yml)
# docker-compose.override.yml โ auto-merged in dev
services:
api:
volumes:
- .:/app # Hot reload
- /app/node_modules
ports:
- "3000:3000"
- "9229:9229" # Debug port
environment:
NODE_ENV: development
LOG_LEVEL: debug
db:
ports:
- "5432:5432" # Expose DB for local tools
environment:
POSTGRES_PASSWORD: devpassProduction Override
# docker-compose.prod.yml โ explicit -f flag needed
services:
api:
restart: unless-stopped
deploy:
resources:
limits:
memory: 512M
cpus: "1.0"
environment:
NODE_ENV: production
LOG_LEVEL: warn
db:
restart: unless-stopped
environment:
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
deploy:
resources:
limits:
memory: 1G
# Usage:
# docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d13. Production Best Practices
Running Docker Compose in production requires careful attention to security, reliability, and performance. Follow these guidelines for stable deployments.
Security Checklist
- Pin image tags โ Never use
:latestin production. Pin to specific versions likepostgres:16.2-alpine. - Externalize secrets โ Use Docker secrets, environment files outside version control, or a secrets manager. Never commit passwords to your Compose file.
- Run as non-root โ Add
user: "1000:1000"or configure your Dockerfile to drop root privileges. - Set read-only filesystem โ Use
read_only: trueon services that do not need to write, and mount tmpfs for temp directories. - Limit network exposure โ Use
internal: trueon backend networks. Bind ports to127.0.0.1unless they need external access. - Drop Linux capabilities โ Use
cap_drop: [ALL]and only add back what you need withcap_add.
Reliability Checklist
- Set restart policies โ Use
restart: unless-stoppedfor all long-running services. - Add health checks โ Every service should have a healthcheck so Compose and monitoring tools can detect failures.
- Use depends_on with conditions โ Ensure services start only after their dependencies are truly ready.
- Set resource limits โ Prevent any single container from consuming all host memory or CPU.
- Configure logging โ Set log drivers and rotation to prevent disk exhaustion.
Production-Ready Template
services:
api:
image: myapp:1.2.3 # Pinned tag
restart: unless-stopped
user: "1000:1000"
read_only: true
tmpfs:
- /tmp
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
deploy:
resources:
limits:
memory: 512M
cpus: "1.0"
reservations:
memory: 256M
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:3000/health || exit 1"]
interval: 30s
timeout: 10s
retries: 3
start_period: 15s
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
depends_on:
db:
condition: service_healthy14. Essential Docker Compose CLI Commands
These are the commands you will use daily when working with Docker Compose:
| Command | Description |
|---|---|
docker compose up -d | Start all services in detached mode |
docker compose down | Stop and remove containers and networks |
docker compose down -v | Also remove named volumes |
docker compose ps | List running containers |
docker compose logs -f api | Follow logs for a specific service |
docker compose exec db psql -U postgres | Open an interactive shell in a running container |
docker compose build --no-cache | Rebuild images without cache |
docker compose pull | Pull latest images for all services |
docker compose restart api | Restart a specific service |
docker compose config | Validate and print the resolved Compose file |
docker compose top | Show running processes per container |
docker compose cp file.txt api:/app/ | Copy files to/from a container |
15. Advanced Compose Features
Docker Compose Watch (Hot Reload)
Compose Watch (introduced in Docker Compose 2.22) automatically syncs file changes and rebuilds services during development:
services:
api:
build: ./api
develop:
watch:
- action: sync
path: ./api/src
target: /app/src
- action: rebuild
path: ./api/package.json
# Usage: docker compose watchResource Limits
services:
api:
deploy:
resources:
limits:
memory: 512M
cpus: "1.5"
reservations:
memory: 256M
cpus: "0.5"
db:
deploy:
resources:
limits:
memory: 1G
cpus: "2.0"
replicas: 1 # Control replica countLogging Configuration
services:
api:
logging:
driver: json-file
options:
max-size: "10m" # Rotate after 10MB
max-file: "5" # Keep 5 rotated files
compress: "true"
# Alternative: send to external logging
worker:
logging:
driver: syslog
options:
syslog-address: "tcp://logserver:514"
tag: "myapp-worker"Init Containers and One-Off Tasks
services:
migrations:
build: ./api
command: ["npx", "prisma", "migrate", "deploy"]
depends_on:
db:
condition: service_healthy
restart: "no" # Run once and exit
seed:
build: ./api
command: ["npx", "prisma", "db", "seed"]
depends_on:
migrations:
condition: service_completed_successfully
restart: "no"
api:
build: ./api
depends_on:
seed:
condition: service_completed_successfully16. Troubleshooting Common Issues
| Problem | Cause | Solution |
|---|---|---|
| YAML parsing error | Indentation mismatch or tab characters | Use spaces only (2-space indent). Run docker compose config to validate. |
| Port already in use | Another process or container using the port | Run lsof -i :PORT or change the host port mapping. |
| Container exits immediately | No foreground process or crash on startup | Check logs with docker compose logs SERVICE. Ensure the command runs in foreground. |
| Volume permissions denied | Container user does not own the mount path | Set the correct user: or fix permissions in Dockerfile. |
| Service cannot reach another service | Services on different networks | Ensure both services share at least one network. Use service name as hostname. |
| Changes not reflected after rebuild | Docker build cache | Run docker compose build --no-cache SERVICE. |
| Out of disk space | Accumulated images, volumes, and build cache | Run docker system prune -a --volumes (caution: removes all unused data). |
Generate Your docker-compose.yml Now
Stop fighting with YAML indentation. Use our visual builder to create production-ready Compose files.
Open Docker Compose GeneratorFrequently Asked Questions
What is a Docker Compose generator and why should I use one?
A Docker Compose generator is an online tool that helps you visually build docker-compose.yml files without memorizing YAML syntax. It prevents indentation errors, validates service configurations in real time, and produces production-ready Compose files in seconds. Using a generator is especially valuable for beginners learning Docker and for experienced developers who want to scaffold new projects quickly.
What is the difference between Compose file version 2 and version 3?
Version 2 was designed for single-host Docker Engine with features like depends_on conditions (service_healthy), resource limits under the service key, and variable substitution. Version 3 was introduced for Docker Swarm compatibility and moved resource constraints into the deploy section. Since Docker Compose V2 (the Go rewrite), the version field is optional and Compose merges features from both schemas automatically.
How do I pass environment variables to containers in Docker Compose?
There are four ways: 1) Inline with the environment key using KEY=value pairs. 2) Reference an external file with env_file pointing to a .env file. 3) Use variable substitution like ${VAR_NAME} which reads from the host shell or a .env file in the project directory. 4) Use Docker secrets for sensitive values in production. The .env file in the same directory as docker-compose.yml is loaded automatically by Compose.
How does depends_on work and can it wait for a service to be healthy?
The depends_on key controls startup order. In its simple form (a list of service names) it only ensures containers start in order, not that they are ready. To wait for actual readiness, use the long-form syntax with condition: service_healthy combined with a healthcheck on the dependency. For example, depends_on: db: condition: service_healthy makes the app wait until the database healthcheck passes.
What are Docker Compose profiles and when should I use them?
Profiles let you selectively start services. You assign profiles to services using the profiles key, and only services with no profile or a matching active profile start by default. Activate profiles with --profile flag or the COMPOSE_PROFILES environment variable. Common use cases include separating debug tools, monitoring stacks, or test databases from the core application services.
How do I use multiple Compose files and override files?
Docker Compose automatically merges docker-compose.yml with docker-compose.override.yml if it exists. You can also specify multiple files with -f flags: docker compose -f docker-compose.yml -f docker-compose.prod.yml up. Later files override earlier ones. This pattern is ideal for maintaining a base config for development and layering production settings like resource limits, restart policies, and external networks on top.
Should I use Docker Compose in production?
Docker Compose works well for single-host production deployments, small to medium applications, and CI/CD pipelines. For production, pin image tags, set restart policies, define resource limits, use health checks, externalize secrets, and configure logging drivers. For multi-host or high-availability needs, consider Kubernetes or Docker Swarm. Many teams use Compose for development and staging while running Kubernetes in production.
How do I generate a docker-compose.yml file online?
Use the free Docker Compose Generator tool on DevToolBox. Select services like PostgreSQL, Redis, or Nginx from the interface, configure ports, volumes, environment variables, and networks visually, then copy the generated YAML. The tool validates your configuration and produces well-formatted, production-ready docker-compose.yml files that you can download or paste directly into your project.