Docker Compose Generator
Build valid docker-compose.yml files visually. Select services, configure ports, volumes, and environment variables, then download your compose file.
Build Your docker-compose.yml
Click services to add them, configure their options, then generate the compose file.
Understanding Docker Compose
Docker Compose is a tool for defining and running multi-container Docker applications using a declarative YAML configuration file. Rather than starting each container manually with docker run commands, you describe your entire application stack in a docker-compose.yml file and manage it with simple commands like docker compose up and docker compose down (Wikipedia: Docker).
The docker-compose.yml file has a straightforward structure. At the top level, you define the version (which corresponds to a specific set of supported features), services (the containers that make up your application), volumes (persistent storage), and networks (communication channels between containers). Each service defines the Docker image to use, port mappings, volume mounts, environment variables, and other container settings.
One of the most valuable features of Compose is service discovery through DNS. When you define multiple services in the same Compose file, Docker creates a network for them and sets up DNS so that each service can reach the others by name. If you have a service called postgres and another called web, the web service can connect to the database using the hostname postgres. This eliminates the need for hardcoded IP addresses and makes configurations portable between environments.
Docker Compose is particularly useful for local development environments. A developer can clone a repository, run docker compose up, and have the entire application stack running on their machine in minutes, regardless of their operating system. This includes the application code, databases, caches, message queues, and any other infrastructure the application needs. It is also widely used in CI/CD pipelines to spin up test environments that mirror production.
Common Service Configurations
PostgreSQL
PostgreSQL is one of the most frequently used databases in Docker Compose setups. The official postgres image accepts environment variables for initial configuration: POSTGRES_PASSWORD sets the superuser password (required), POSTGRES_USER sets a custom username (defaults to postgres), and POSTGRES_DB creates a database on first start. Always mount a named volume to /var/lib/postgresql/data to persist your database between container restarts. The default port is 5432, which you can map to any host port. For production, add a healthcheck using pg_isready so dependent services can wait for the database to be fully ready before connecting.
Redis
Redis requires minimal configuration in most setups. The official redis image works out of the box, with the default port being 6379. For persistence, mount a volume to /data and pass the --appendonly yes flag in the command directive. This enables AOF (Append Only File) persistence, which logs every write operation and can reconstruct the dataset on startup. For caching-only use cases where persistence is not needed, you can skip the volume. Redis also supports password authentication via the --requirepass flag, which you should enable in any environment where the Redis port is exposed outside the Docker network.
MongoDB
MongoDB's official image uses MONGO_INITDB_ROOT_USERNAME and MONGO_INITDB_ROOT_PASSWORD for initial setup. The data directory is /data/db, which should be mounted to a named volume. The default port is 27017. MongoDB stores its data as BSON files on disk, and the volume ensures these survive container recreation. For development, you might also want to add mongo-express as a companion service, which provides a web-based admin interface for browsing your MongoDB databases and collections.
Nginx
Nginx in Docker Compose typically serves as a reverse proxy in front of application containers. Mount your nginx configuration file to /etc/nginx/conf.d/default.conf using a bind mount, and your static files to the appropriate directory. When using nginx as a reverse proxy for other Compose services, use the service name as the proxy_pass hostname. For example, if your Node.js service is named api, use proxy_pass http://api:3000 in your nginx config. The standard ports are 80 for HTTP and 443 for HTTPS.
Node.js and Python Applications
Application services typically use a Dockerfile rather than a pre-built image. Set the build context using the build directive pointing to the directory containing your Dockerfile. For development, mount your source code as a bind volume and use a tool like nodemon (Node.js) or watchdog (Python) to auto-restart on file changes. The working_dir directive sets the working directory inside the container. Environment variables for database connection strings and API keys are set using the environment directive or loaded from an .env file. Always specify a depends_on directive for database and cache services that your application needs.
Volumes and Networks
Volumes and networks are the two infrastructure components that tie your Docker Compose services together. Understanding them properly is critical for building reliable containerized applications.
Named Volumes vs Bind Mounts
Named volumes are created and managed by Docker. You define them in the top-level volumes section and reference them in service volume mounts. They persist independently of container lifecycle and survive docker compose down (unless you use the -v flag). Named volumes are stored in Docker's managed storage area and are the recommended approach for database data, as they provide consistent performance across operating systems.
Bind mounts map a specific host filesystem path into a container. They are defined using the host_path:container_path syntax. Bind mounts are ideal for development because changes to source code on the host are immediately visible inside the container. However, they have performance issues on macOS and Windows because Docker runs in a VM on these platforms, and file system operations between the host and VM incur overhead. For development with many files (like a node_modules directory), consider using a named volume for the dependency directory while bind-mounting only the source code.
Custom Networks
Docker Compose creates a default network for all services in the file, but you can define custom networks for more control. Custom networks are useful when you want to isolate groups of services from each other. For example, you might have a frontend network connecting nginx to your web application and a backend network connecting the application to databases. Services can be attached to multiple networks. Services that share no network cannot communicate with each other, providing a layer of isolation that mimics real network segmentation (Docker Compose Networking Documentation).
Environment Variables and Secrets
Proper handling of environment variables and secrets is one of the most important aspects of Docker Compose configuration for any project that will see production use. The naive approach of hardcoding passwords directly in the docker-compose.yml file works for quick prototypes but creates security and operational problems.
The recommended approach is to use a .env file for variable substitution. Create a file named .env in the same directory as your docker-compose.yml (Docker Compose reads this file automatically) and define your variables there. Then reference them in your Compose file using the ${VARIABLE_NAME} syntax. This separation means your Compose file can be committed to version control while the .env file is listed in .gitignore to keep secrets out of your repository.
For teams, create an .env.example file with placeholder values that documents all required variables without exposing actual secrets. New team members copy this to .env and fill in the real values. This pattern is standard practice across the industry and works well for most development and small deployment scenarios.
For production environments with stricter security requirements, Docker Swarm's secrets feature or external secret management tools like HashiCorp Vault or AWS Secrets Manager are better options. These systems encrypt secrets at rest and in transit and provide access control and audit logging that environment variables alone cannot offer.
Production Best Practices
Image Tags
Never use the latest tag in production docker-compose.yml files. The latest tag is mutable, meaning the image it points to changes over time. This makes your deployments non-reproducible, as running docker compose pull on two different days might give you different images. Instead, pin specific version tags. For PostgreSQL, use postgres:16.2 instead of postgres:latest. For your own application images, use git commit hashes or semantic version tags as image tags.
Resource Limits
Set memory and CPU limits for each service to prevent a single runaway container from consuming all system resources. In Compose file version 3, use the deploy.resources.limits section under each service. For example, setting memory to 512M and cpu to 0.5 limits the container to 512 megabytes of RAM and half a CPU core. Without limits, a memory leak in one service can cause the entire host to run out of memory, taking down all containers.
Restart Policies
Set restart: unless-stopped or restart: always on every production service. Without a restart policy, containers that crash or that stop because the host rebooted will not automatically come back. The unless-stopped policy restarts the container automatically unless it was manually stopped by the operator, which is usually the desired behavior for production services.
Logging
Configure logging drivers and limits to prevent log files from consuming all disk space. The default json-file logging driver has no size limit, so long-running containers with verbose logging can fill up the disk. Add a logging section to each service with max-size (for example, 10m for 10 megabytes) and max-file (for example, 3 to keep 3 rotated log files). For centralized logging, consider using the syslog, fluentd, or gelf logging drivers to forward logs to an aggregation service.
Community Questions
What is the difference between docker-compose up and docker-compose run?
A frequently asked question about the two different ways to start services. The answers explain that up starts all services defined in the Compose file (or specified services plus their dependencies), while run starts a single service and executes a one-off command.
View on Stack OverflowHow to wait for a database to be ready in Docker Compose?
Covers the common problem of application containers starting before the database is ready to accept connections. Answers discuss depends_on with healthchecks, wait-for-it scripts, and application-level retry logic.
View on Stack OverflowHow to access the host machine from a Docker container?
When your containerized application needs to reach a service running on the host machine, the networking setup is not straightforward. This thread covers host.docker.internal, network_mode: host, and other approaches for different operating systems.
View on Stack OverflowVideo Tutorials
Helpful Videos on Docker Compose
Complete introduction to Docker Compose covering file syntax, common services, volumes, networks, and practical examples.
Building a real-world multi-service application stack from scratch using Docker Compose with database migrations and seed data.
Covers resource limits, restart policies, logging, secret management, and monitoring for production Docker Compose deployments.
Frequently Asked Questions
Docker Compose is a tool for defining and running multi-container Docker applications. You define all services, networks, and volumes in a single YAML file and start everything with docker compose up. It documents your infrastructure as code, manages container lifecycles together, automatically creates networks so services communicate by name, and handles dependency ordering with depends_on. For example, your Node.js app can reach PostgreSQL using the hostname postgres instead of an IP address. Compose is the standard for local development environments, CI/CD pipelines, and simple production deployments. It replaces complex docker run commands with a readable, version-controlled configuration file.
The hyphenated docker-compose is the older standalone Python-based tool (V1), while docker compose with a space is the newer Go-based CLI plugin (V2). V2 has been the default since Docker Desktop 4.x and Docker Engine 20.10+. Both read the same docker-compose.yml format. V2 uses underscores instead of hyphens in container names by default, and some edge-case flags differ. Docker deprecated V1 in April 2023 and it reached end of life in June 2023. Always use docker compose (V2 syntax) for new projects. If you have existing scripts using the hyphenated form, they work with V1 installed but you should plan to migrate. The YAML file syntax is identical between versions.
Without volumes, data inside containers is lost when the container is removed. Named volumes are defined in the top-level volumes section and mounted in services. For PostgreSQL, mount a volume to /var/lib/postgresql/data. Named volumes are managed by Docker, stored in Docker's storage area, and persist across container recreations. Bind mounts map host directories to container paths and are useful for development (mounting source code). For databases, always use named volumes because they have better performance on macOS and Windows. Volumes survive docker compose down unless you explicitly use the -v flag. This separation means you can rebuild containers freely without losing data.
Docker Compose automatically creates a bridge network for all services in the same file. Services reach each other using the service name as a hostname through Docker's built-in DNS. If you have services web and postgres, the web service connects using postgres as the hostname and the internal container port (not the published host port). The connection string looks like postgres://user:password@postgres:5432/mydb. The ports directive maps container ports to host ports for external access, but internal communication uses the container network directly. You can define custom networks to isolate groups of services from each other.
Compose supports environment variables in several ways. The environment key sets variables directly in the YAML file. For sensitive values, create a .env file (Docker Compose reads it automatically) and reference variables using ${VARIABLE_NAME} syntax. The env_file directive loads variables from a named file. Never commit .env files to version control. Instead, create .env.example with placeholder values as documentation. Precedence order: shell environment values override .env file values, which override Compose file defaults. This layering lets you use different configurations for dev, staging, and production without changing the Compose file.
No, depends_on only waits for the container to start, not for the service inside to be ready. A PostgreSQL container might take seconds after starting before accepting connections. If your app connects immediately, it fails. Solutions: add retry logic with exponential backoff to your application startup (recommended), or use depends_on with the service_healthy condition and define a healthcheck on the database service. For PostgreSQL, a healthcheck running pg_isready makes Compose wait until the database is actually accepting connections. This is more reliable than arbitrary sleep commands in entrypoint scripts.
The simplest method is docker compose up -d, which only recreates containers whose configuration or image changed. Pull latest images first with docker compose pull. For zero-downtime updates, scale up temporarily with --scale, then scale back down. However, Compose is designed for single-host deployments and lacks rolling update capabilities. For true zero-downtime production deployments, consider Docker Swarm (supports rolling updates natively) or Kubernetes. For development and small production setups, the brief interruption from docker compose up -d is usually acceptable. Always test updates in staging first and have a rollback plan.
Compose works for small to medium production deployments on a single server. Many startups run production workloads this way successfully. Limitations: no automatic restart across reboots without restart policies, no multi-host support, no built-in health monitoring or auto-scaling, and no rolling updates. For production, always set restart policies, use named volumes, avoid bind mounts, set memory limits, use specific image tags (never latest), and handle secrets properly. If you outgrow single-server Compose, the natural migration path is Docker Swarm (easiest from Compose) or Kubernetes (more capable but more complex). Start with Compose and migrate when you need multi-host or auto-scaling.
Sources and References
Quick Facts
- 100% free, no registration required
- All processing happens locally in your browser
- No data sent to external servers
- Works offline after initial page load
- Mobile-friendly responsive design