Docker Compose Builder
Describe your services in a form and get a valid, correctly-indented docker-compose.yml — generated in your browser.
Examples
Default two-service stack (nginx + postgres)
service web:
image: nginx:latest
ports: 80:80
restart: unless-stopped
depends: db
service db:
image: postgres:16
volumes: pgdata:/var/lib/postgresql/data
environment: POSTGRES_PASSWORD=secret
POSTGRES_DB=app
restart: unless-stoppedservices:
web:
image: nginx:latest
ports:
- "80:80"
depends_on:
- db
restart: unless-stopped
db:
image: postgres:16
volumes:
- pgdata:/var/lib/postgresql/data
environment:
- POSTGRES_PASSWORD=secret
- POSTGRES_DB=app
restart: unless-stopped
volumes:
pgdata:The builder quotes every port mapping so a value like `8080:80` is never misread as a number. Named volumes (`pgdata`) are detected by the regex `^[a-zA-Z0-9][\w.-]*$` and collected into a top-level `volumes:` block; bind-mounts that start with `.` or `/` are left inline only.
Single service — bind-mount, env, command, restart
service api:
image: node:20-alpine
command: node server.js
ports: 3000:3000
volumes: ./data:/app/data
environment: NODE_ENV=production
restart: alwaysservices:
api:
image: node:20-alpine
command: node server.js
ports:
- "3000:3000"
volumes:
- ./data:/app/data
environment:
- NODE_ENV=production
restart: alwaysWith one service and no named volumes, no top-level `volumes:` block is emitted. The restart policy is included only when it is not `no`, the command is emitted verbatim, and the environment is written as the list form (`- KEY=value`) so values containing `=` are preserved.
Three-service stack with a shared dependency chain
service api:
image: node:20-alpine
ports: 3000:3000
9000:9000
environment: NODE_ENV=production
DATABASE_URL=postgres://user:pass@db:5432/app
REDIS_URL=redis://cache:6379
depends: db, cache
restart: always
service db:
image: postgres:16-alpine
volumes: pgdata:/var/lib/postgresql/data
environment: POSTGRES_PASSWORD=secret
restart: unless-stopped
service cache:
image: redis:7-alpine
volumes: redisdata:/data
restart: alwaysservices:
api:
image: node:20-alpine
ports:
- "3000:3000"
- "9000:9000"
environment:
- NODE_ENV=production
- DATABASE_URL=postgres://user:pass@db:5432/app
- REDIS_URL=redis://cache:6379
depends_on:
- db
- cache
restart: always
db:
image: postgres:16-alpine
volumes:
- pgdata:/var/lib/postgresql/data
environment:
- POSTGRES_PASSWORD=secret
restart: unless-stopped
cache:
image: redis:7-alpine
volumes:
- redisdata:/data
restart: always
volumes:
pgdata:
redisdata:Multiple ports are split on newlines or commas into separate list items. The `dependsOn` field is tokenised the same way and emitted as a YAML list. Named volumes `pgdata` and `redisdata` are gathered and emitted under a single `volumes:` block at the bottom of the file.
About this tool
docker-compose.yml is easy to break: YAML is indentation-sensitive, an unquoted port mapping can be misread, and a mis-nested key can stop a whole stack from coming up. This builder lets you describe services in a form and generates correctly-indented, spec-compliant Compose YAML you can drop straight into a project.
Add as many services as you need and configure the image, published ports, bind-mount and named volumes, environment variables, a restart policy, a command override and depends_on relationships. The tool quotes port mappings so values like 8080:80 aren't misread, collects named volumes into the top-level volumes: block automatically, and follows the modern Compose specification (no obsolete version: key). The YAML updates live and everything is generated in your browser.
How to use
Add your services
Create a service per container and set its image (e.g. nginx:latest, postgres:16).
Configure each service
Add ports, volumes, environment variables, a restart policy and depends_on links.
Watch the YAML build
The docker-compose.yml regenerates live as you edit, with named volumes gathered automatically.
Copy or download
Copy the YAML or download docker-compose.yml ready to run with docker compose up.
Use cases
Scaffolding a local dev environment
Add a web, api, db and cache service, paste the published ports and bind-mounts you need, and run `docker compose up` — the builder produces a single, correctly-indented YAML file ready to commit.
Translating a manual YAML into a reproducible form
When a docker-compose.yml has grown by hand-edits, paste the same services into the builder, save the result, and diff it against the original to catch unquoted ports and stray tabs that YAML parsers don't always accept.
Building a minimal smoke-test stack
Two services — one app, one database — with no bind-mounts, no named volumes, and `restart: no` is enough to verify a Docker image works locally. The builder makes that one-screen configuration effortless.
Documenting a deployment topology
Express a known stack as a Compose file once and keep it in the repo; readers can run the same services locally to reproduce a staging or production setup.
Per-service options
| Field | Compose key |
|---|---|
| Image | image: |
| Ports | ports: (quoted host:container mappings) |
| Volumes | volumes: (bind mounts + named volumes) |
| Environment | environment: (KEY=value list) |
| Restart | restart: (no / always / on-failure / unless-stopped) |
| Depends on | depends_on: (startup ordering) |
Follows the current Compose spec — no obsolete version key.
Common mistakes
Mistake:Writing unquoted port mappings like `8080:80` and getting a YAML parse error.
Fix:Unquoted, `8080:80` is parsed by some YAML loaders as the sexagesimal number `8080:80` (≈ 8,080 × 60 + 80). The builder always quotes port mappings (`- "80:80"`) — trust the output and don't strip the quotes.
Mistake:Listing a bind-mount (`./data:/app/data`) as a named volume.
Fix:The builder decides by prefix: `./` and `/` mean a host bind-mount, anything else is a named volume. Use `./data` or an absolute path to keep the source on the host, and only use bare identifiers when you want Docker to manage the volume.
Mistake:Adding a `version: '3'` key to the top of the YAML.
Fix:The current Compose spec deprecates the `version` key — it is ignored by `docker compose` and triggers a warning in modern installs. The builder deliberately omits it; don't add it back when you hand-edit the file.
Mistake:Forgetting to set `restart: unless-stopped` on a long-running service.
Fix:Without a restart policy, a service that crashes stays down until you `docker compose up` again. The builder defaults to `no`, so any production-style service needs an explicit `always`, `on-failure` or `unless-stopped`.
Frequently asked questions
Related guides
From docker run to docker-compose.yml: Converting One-Off Commands into Versioned Files
Why a checked-in Compose file beats a one-liner in your shell history, the exact flag-to-key mapping the converter uses, and the gotchas worth knowing when you migrate.
A Sane Starting Point for docker-compose.yml
The Compose fields you actually need — services, ports, volumes, environment, depends_on and restart policies — without the YAML foot-guns.
References & standards
Related tools
.htaccess Generator
Build an Apache .htaccess — HTTPS redirects, rewrites, error pages, security headers, and basic auth
Ansible Playbook Generator
Build an Ansible playbook — hosts, vars, and tasks with modules — as YAML
Apache Config Generator
Build an Apache 2.4 VirtualHost — ServerName, DocumentRoot, Directory, aliases, and optional SSL
AWS Architecture Diagram
Drag-and-drop AWS service blocks, connect edges and export architecture diagrams as SVG
AWS Pricing Calculator
Estimate monthly AWS costs from static list prices with a Chart.js breakdown
Azure Architecture Diagram
Compose Azure architecture diagrams with VM, Storage, Functions, AKS blocks and SVG export