docker-compose port-collision checker
Paste one or more Compose files and read every published host port, the collisions between them, the privileged ports and the ports the host picks.
What it computes. Paste one Compose file, or several one after another, and the checker reads every ports: entry under services:. For each mapping it shows the service, the file it came from, the host address and port that will be bound, the container port, the protocol, and a status. Then it looks across every file for the one thing that stops a stack from starting: two mappings that try to bind the same host port on the same protocol. The collisions are listed first, by port, with the services on both sides; privileged ports below 1024 are flagged, because binding them needs a capability the runtime may not have; mappings with no host port are listed as the host's to pick; and a variable the page cannot see is shown unresolved rather than guessed.
The method. The checker follows the Compose Specification's grammar for the short syntax, [HOST:]CONTAINER[/PROTOCOL], where the host part is an optional address followed by a port or a range, the container part is a port or a range, and the protocol defaults to TCP. Equal-length ranges map port by port; a host range against a single container port means the runtime will choose one free port from the range, so such an entry can only possibly collide, and the checker says so. The long syntax is read from its fields: target, published, host_ip and protocol. A mapping with no host address binds every interface, so it collides with any mapping of the same port on any address; two mappings on two different specific addresses do not collide. TCP and UDP are separate namespaces. Environment variables with a default, ${PORT:-8080}, take the default and say so.
A worked example. The first example pastes two files. The web stack publishes 80, 443, loopback 8080 and 3000; the media stack publishes 8096, 8080 on every interface, UDP 1900, 3000 in long syntax, a variable with a default of 9090, and a range 8000–9000 for one container port. The checker reports two collisions — 8080, where the wildcard bind covers the loopback bind, and 3000, published by both files — flags 80 and 443 as privileged, applies the 9090 default, and warns that the 8000–9000 range may land on a port the stack already uses.
The edge cases. The same port named twice inside one service is a collision like any other. IPv6 host addresses are read bare, ::1:6000:6000, or in brackets; 0.0.0.0 and :: count as every interface. A network_mode: host service with a ports: list is flagged, because the specification calls that combination a runtime error. A service that uses extends: is read for its own ports only. YAML is read in its plain block and flow forms with quoted or plain scalars; anchors, aliases and merge keys are refused by name so that nothing is dropped in silence. A document without services: is skipped and said to be skipped.
What this tool cannot know. It sees the text you paste and nothing else: not the .env file, not the shell that will run docker compose up, so a port set only by a variable is reported unresolved. It does not know what already listens on your host outside Compose — a system service on port 80 collides just as surely, and this page cannot see it. Ports inherited through extends:, exposed only by a Dockerfile, or opened by a network_mode: host process are not listed. Profiles are not evaluated: a service behind a profile is read as if it will start. A collision found here is certain only for mappings with fixed host ports on overlapping interfaces; the runtime's own validation remains the final word.
Run the self-test
Runs the known-answer table on this page, in your browser, against the same engine you just used. The known-answer table holds thirty-seven cases: the specification's eleven short-syntax examples and its long-syntax example, the collision rules, and the rejected inputs.
Method v1.0, 2026-11-13. Authorities: the Compose Specification's ports attribute (short and long syntax; compose-spec/compose-spec, read 2026-11-13), bind(2) for the collision rule (EADDRINUSE).