Docker Compose Validator & Service Graph
Catch host-port collisions, circular dependencies, readiness gaps, and outdated syntax — then see the architecture as an interactive service graph. Everything runs locally.
- 3 services parsed.
- 2 dependencies ordered only by startup, not by health/readiness.
- 2 required environment variables need values.
- All services share the default network.
Quick answers for the questions most Compose files run into
Short, practical answers you can apply directly to acompose.yamlfile. Every section below is based on the current Compose specification.
How do I visualize a Docker Compose file?
Parse the YAML into a Compose model (services, networks, volumes, secrets, configs), then render four overlapping but distinct relationships: startup dependencies (depends_on), shared-network reachability (service-name DNS across a network), resource attachment (named volumes, secrets, configs), and any legacy constructs (links, volumes_from, network_mode: service:…). Draw them with separate edge styles so a reader can instantly tell the difference between “A starts before B” and “A can talk to B” — those are not the same thing.
What does depends_on actually do?
The short-form depends_on: [db] controls startup and shutdown ordering only. Compose guarantees db is started before the dependent service, and torn down after it. It does not wait for the container to be ready to accept connections.
Readiness requires long-form depends_on with a condition:
service_started— same as short formservice_healthy— waits for the target's healthcheck to report healthyservice_completed_successfully— waits for a one-shot container (like a migrator) to exit cleanly
Compose also takes links, volumes_from, and network_mode: "service:…" into account when deriving startup order — which is why a cycle involving those constructs can also block docker compose up.
Compose error cheat sheet
| Compose issue | Why it happens | What to do |
|---|---|---|
| Port collision | Two services publish the same host IP + host port + protocol. Docker allows only one owner per binding. | Change one host port, bind to a specific host IP, or remove the duplicate publish. |
| Circular dependency | A cycle across depends_on, links, volumes_from, or network_mode: service:… leaves Compose without a valid startup order. | Remove one edge: introduce a broker, move to healthcheck-gated depends_on on only one side, or split a service. |
| Startup without health readiness | Short-form depends_on only orders startup. The dependent service may run before the target is actually accepting connections. | Add a healthcheck to the target and use long-form depends_on with condition: service_healthy. |
| Undefined env variable | A ${VAR} is interpolated with no fallback. Compose silently substitutes an empty string, usually breaking connection strings and image tags. | Provide a value via .env, --env-file, shell export, or add a :- fallback. Use Compose secrets for sensitive values. |
| Obsolete version: field | Modern Compose ignores the top-level version:. It is accepted for backwards compatibility but misleads readers. | Delete the version: line. Compose v2 derives capabilities from the installed engine. |
| Legacy links: | links: is a legacy compatibility feature from the original Docker networking model. Modern bridge networks already resolve service names via DNS. | Remove links: and rely on service-name DNS across a shared network. Use aliases: on the network attachment for alternate names. |
| Undefined network / volume / secret / config | A service references a top-level resource that is not declared. Compose refuses to run with an undefined resource. | Add the missing top-level declaration, mark it external: true if managed outside Compose, or fix the typo. |
Modern Compose best-practice dependency snippet
The canonical way to make an app wait for a database to be genuinely ready: a real healthcheck on the target, plus long-form depends_on with condition: service_healthy.
services:
api:
image: myorg/api:latest
environment:
DATABASE_URL: postgres://app:app@db:5432/app
depends_on:
db:
condition: service_healthy
db:
image: postgres:16
environment:
POSTGRES_DB: app
POSTGRES_USER: app
POSTGRES_PASSWORD: app
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app -d app"]
interval: 5s
timeout: 3s
retries: 10
start_period: 10s
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:With this shape, Compose starts db first, polls its healthcheck until it reports healthy, and only then starts api. You get predictable startup without shell-script retry loops.
Why a service graph is better than reading the YAML
YAML is a good serialization format but a poor architecture review surface. Once a file passes four or five services it becomes hard to answer simple questions by scrolling: which services share a network?, who actually mounts this volume?, is there a dependency cycle?, who talks to the database?.
A service graph forces those relationships to be explicit and makes hidden coupling jump out. That helps in four concrete ways:
- Architecture review. Reviewers see the shape of the stack at a glance instead of pattern-matching on indentation.
- Handoff & documentation. New teammates and open-source contributors get oriented in seconds; the diagram is a README-grade artifact.
- Faster detection of hidden coupling. Cycles and multi-network bridges stand out visually, even when the YAML looks innocent.
- Better READMEs and wikis. Exporting an SVG or PNG turns the graph into a real, versioned asset for your internal or open-source docs.
Local-only processing
In this version, your Compose file never leaves your browser. Parsing, validation, and graph rendering all run client-side; nothing is uploaded, logged, or sent to a server. This matters because Compose files routinely expose private image names, internal service names, ports, networks, registry URLs, and secret references — even without raw credentials, that metadata alone can be sensitive. Still, follow your organisation's policy before pasting confidential infrastructure definitions into any browser tool.
Compose files are parsed locally in your browser. Nothing you paste is uploaded, stored, or sent to a server.
Overview
A Compose file starts simple — an app, a database, maybe a cache — but grows surprisingly fast. Once you have workers, a broker, migrations, multiple networks, and three services sharing a volume, the YAML stops reflecting the architecture in any readable way. Two services quietly end up publishing the same host port; a cycle sneaks in through a legacy links: entry; an API is ordered to start after a database but not actually waiting for it to be ready. None of these fail YAML validation, so a plain linter misses them.
This tool fills that gap. It parses your Compose file with a Compose-aware understanding of services, networks, volumes, configs, secrets, and profiles, then runs a set of semantic checks drawn from the current Compose specification: host-port collision (including host IP, protocol, and port ranges), circular dependency across depends_on and legacy constructs, readiness gaps, environment interpolation, and undefined references to volumes, secrets, or networks. Findings are ranked from Critical to Informational with plain-English explanations and suggested fixes — not just error codes.
A visual service graph sits alongside the validator. Startup dependencies, shared-network reachability, and resource attachments each get their own edge styling, so “A starts before B” is never visually conflated with “A can reach B over the network” — two very different Compose semantics that linting tools usually merge. You can filter by node or edge type, highlight problem services, and export the diagram as SVG or PNG for READMEs and wikis. The whole thing runs locally in your browser; no Compose file is ever uploaded.
Use cases
When to use it
- Spot host-port conflictsTwo services trying to bind 8080/tcp is the fastest way to a broken docker compose up.
- Find circular dependenciesAcross depends_on, links, volumes_from, and network_mode: service:… so cycles that hide in legacy constructs still surface.
- Review readiness gapsSee which dependencies only order startup versus which actually wait for a healthcheck-gated readiness signal.
- See the network topology clearlyUnderstand which services can reach each other by service name versus which are isolated behind custom networks.
- Document open-source or internal stacksExport an SVG or PNG for your README, wiki, or design doc instead of hand-drawing another diagram.
- Audit required env vars and shared resourcesGet a ready-to-fill .env checklist and a list of every declared volume, secret, and config the services rely on.
When it's not enough
- Runtime debuggingThis is a static analyser. For runtime issues use docker compose logs, docker compose ps, and docker inspect.
- Production deployment validationCompose is excellent for local development and small deployments; for production orchestration use Kubernetes, ECS, or Nomad, each with their own validators.
- Schema migration checksThe tool does not run SQL, execute migrations, or validate data models. It reads your Compose file only.
How to use it
- 1
Paste your Compose file (or load an example)
Drop in compose.yaml / docker-compose.yml, upload a file, or pick one of the built-in samples to see what findings look like.
- 2
Read the summary card
A few plain-English bullets at a glance: how many services parsed, whether ports collide, whether there are cycles, and how many required env vars you need to provide.
- 3
Walk the issues panel
Findings are ranked Critical, Warning, Recommendation, Informational. Each has a plain-English detail and a suggested fix. Critical issues block docker compose up; warnings and recommendations are quality improvements.
- 4
Inspect the service graph
Click a service to see its neighbours and highlighted edges. Filter by node type (services, networks, volumes, secrets, configs) or edge kind to reduce visual noise on larger stacks.
- 5
Fix collisions, tighten readiness, add healthchecks
Resolve any port collision first. Then add real healthchecks to critical dependencies (databases, brokers) and switch short-form depends_on to condition: service_healthy.
- 6
Export the diagram and env checklist
Download the service graph as SVG or PNG for your README and copy the generated .env template for teammates.
Common errors and fixes
depends_on fires before the database is ready
Add a healthcheck to the database service (e.g. pg_isready, redis-cli PING, or an HTTP probe) and use long-form depends_on with condition: service_healthy. Short-form depends_on only orders startup, not readiness.
Container fails to start with an address-already-in-use error
Two services are publishing the same host IP + host port + protocol. Change one of the host ports, or bind them to different host IPs. Note that 0.0.0.0 is a wildcard and collides with any specific IP on the same port.
Compose refuses to run with `services cannot be started in order`
A dependency cycle exists. Check depends_on, links, volumes_from, and network_mode: service:…. Break the cycle by removing one of the edges, introducing a message broker, or splitting a service that plays two roles.
`Compose does not know about the version: field` hints in logs
The top-level version: key is obsolete in modern Compose. It is accepted for backwards compatibility but no longer required. Remove it to stop misleading readers.
Services cannot reach each other by name after adding custom networks
Declaring a custom networks: list on a service disables the implicit default network for that service. Make sure the peer services share at least one network, or add `default` to the service's networks list.
Undefined named volume / secret / config at runtime
A service references a resource that is not declared at the top level. Add the missing top-level entry, mark it external: true if it is managed outside this Compose project, or fix the typo.
Sensitive values are leaking into `docker inspect`
Switch from environment: to Compose secrets: for passwords, tokens, and API keys. Secrets are mounted as files under /run/secrets/<name> and are not visible in inspect output.
Frequently asked questions
Related
Working on the network ranges your containers sit on? Pair this validator with the visual subnet calculator to plan VPC and CIDR layouts, then come back here to validate the container services running on top of them. Automating scheduled workloads? Build them with the AWS EventBridge schedule builder or cron parser, and validate the local stack that runs them here. Already have a JSON or YAML config you trust syntactically? Syntax is only the first step — the JSON ↔ YAML converter and JSON formatter help with the shape; this tool validates the architectural semantics.