Docker Compose Generator

One line per service in, a complete docker-compose.yml out — ports quoted correctly, named volumes and networks declared for you, and every dependency checked before a byte of YAML is written. Nothing is uploaded.

Try:
docker-compose.yml

About this tool

Docker Compose Generator turns a short, paste-able spec — one line per service — into a complete docker-compose.yml. Instead of clicking through a form for every port and volume, you write what you already know:

web: nginx:alpine ports=8080:80 depends=api
api: ghcr.io/acme/api:v1 ports=3000 env=PORT=3000
db: postgres:16-alpine volumes=dbdata:/var/lib/postgresql/data env=POSTGRES_PASSWORD=secret

Everything runs in your browser through WebAssembly, so image names, passwords and internal hostnames never leave your machine.

The generator does the bookkeeping that hand-written compose files usually get wrong: named volumes and networks referenced by any service are collected into the top-level volumes: and networks: sections, depends_on targets are checked against the services you actually declared, and every port mapping and environment value is emitted quoted so YAML cannot silently reinterpret it.

Spec format

Each line is name: image [key=value ...]. Blank lines and lines starting with # are ignored. Wrap any value containing a space or a comma in double quotes — command="npm run start".

OptionWhat it does
image=Image reference. Also accepted bare, right after the colon.
build=Build context path, instead of (or alongside) an image.
ports=Comma-separated 8080:80, 3000, 127.0.0.1:5432:5432, 8000-8005:8000-8005, 53:53/udp.
expose=Container-only ports, not published to the host.
volumes=Comma-separated src:/container/path[:ro]. A source that is not a path becomes a named volume.
env=Comma-separated KEY=value.
env_file=Comma-separated env file paths.
depends=Other service names from the same spec.
restart=no, always, on-failure or unless-stopped.
command= / entrypoint=Override the image's command or entrypoint.
container_name=, user=, working_dir=Fixed container name, run-as user, working directory.
networks=Networks for this service, overriding the shared one.
labels=Comma-separated key=value metadata.
healthcheck=A shell command, emitted as a CMD-SHELL test with 30s interval, 10s timeout, 3 retries.

File-wide settings

Worked example

Spec (above), project name shop, shared network appnet, default restart unless-stopped:

name: shop
services:
  web:
    image: nginx:alpine
    restart: unless-stopped
    ports:
      - "8080:80"
    networks:
      - appnet
    depends_on:
      - api
  api:
    image: ghcr.io/acme/api:v1
    restart: unless-stopped
    ports:
      - "3000"
    environment:
      PORT: "3000"
    networks:
      - appnet
  db:
    image: postgres:16-alpine
    restart: unless-stopped
    environment:
      POSTGRES_PASSWORD: "secret"
    volumes:
      - dbdata:/var/lib/postgresql/data
    networks:
      - appnet
volumes:
  dbdata:
networks:
  appnet:
    driver: bridge

Save it as docker-compose.yml and run docker compose up -d.

Limits and edge cases

FAQ

Why are my ports wrapped in quotes?

Because unquoted they are not strings. In YAML, 22:22 is a sexagesimal (base-60) number that parses as 1342, which is why hand-written compose files occasionally publish a port nobody asked for. Every port mapping here is emitted double-quoted, so - "22:22" stays exactly what you wrote. Environment values are quoted for the same reason: DEBUG=true becomes DEBUG: "true", a string, not a boolean.

Do I still need a `version:` key at the top?

No. The current Compose specification dropped it, and recent docker compose versions warn that it is obsolete — so it is omitted by default. The dropdown is there only for the old standalone docker-compose v1 binary, which refuses a file without one. If you are unsure, leave it on "Omit".

When does a volume end up in the top-level `volumes:` section?

When its source is a name rather than a path. dbdata:/var/lib/postgresql/data mounts the named volume dbdata, so dbdata: is declared at the top level — without that declaration Docker rejects the file. ./site:/usr/share/nginx/html is a bind mount of a host directory, so nothing is declared. Sources starting with /, ./, ../, ~ or $ are treated as paths.

How do I write a command or an environment value that contains spaces?

Put double quotes around it. The spec is split on whitespace, so command=npm run dev would read run and dev as unknown options; command="npm run dev" keeps them together. The same applies inside comma-separated lists — env=GREETING="hello, world" keeps the comma out of the list split.

Does `depends_on` wait for the service to be ready?

Not by itself. Plain depends_on only orders startup — the dependent container starts once the other has been created, not once it is accepting connections. That is why the spec also has healthcheck=: give the dependency a real readiness command (healthcheck="pg_isready -U postgres"), then edit the generated depends_on list into the long form with condition: service_healthy if you need Compose to actually wait.

What happens if a service depends on one that does not exist?

You get an error naming both services, and no YAML at all. The same is true for an invalid port, a container path that is not absolute, a duplicate service name, an unknown restart policy, or a service that depends on itself. The tool would rather refuse than hand you a file that docker compose up rejects three minutes later.

Is the output stable enough to commit?

Yes. Services appear in spec order, and the derived volumes: and networks: sections are sorted, so the same input always produces byte-identical output. That makes the generated file safe to check in and re-generate — a diff only shows what you actually changed in the spec.

Developer & Automation Access

Run it from the terminal

Same engine as this page, headless — via the gizza CLI:

gizza tool docker-compose-generator "web: nginx:alpine ports=8080:80 depends=api
api: ghcr.io/acme/api:v1 ports=3000 env=PORT=3000
db: postgres:16-alpine volumes=dbdata:/var/lib/postgresql/data"

New to the CLI? Get gizza →

Open it by URL

Pre-fill and auto-run this tool with query parameters — the names match the API/CLI:

https://gizza.ai/tools/docker-compose-generator/?services=web%3A%20nginx%3Aalpine%20ports%3D8080%3A80%20depends%3Dapi%0Aapi%3A%20ghcr.io%2Facme%2Fapi%3Av1%20ports%3D3000%20env%3DPORT%3D3000%0Adb%3A%20postgres%3A16-alpine%20volumes%3Ddbdata%3A%2Fvar%2Flib%2Fpostgresql%2Fdata&project_name=shop&compose_version=none&network=appnet&network_driver=bridge&restart=none&env=TZ%3DUTC%0ALOG_LEVEL%3Dinfo&env_file=.env

Machine-readable descriptor: tool.json — title + parameters JSON Schema for agents.