Every multi-service repo I touch has the same onboarding failure mode: clone, run the happy-path start command, get EADDRINUSE or a silent hang because Postgres is mapped to 5433 in Compose and 5432 in someone's muscle memory.
The ports are not secret. They are scattered across docker-compose.yml, .env.example, package.json scripts, Vite/Next configs, Spring application.yml, Kubernetes manifests, and the README that went stale six months ago. Runtime tools answer a different question: what is listening right now? After a fresh clone, nothing is listening yet. You need the project's declared ports.
What I built
projports is a small Go CLI that walks a repository and prints every port it can find in configuration — offline, no Docker daemon required, with -json for agents and CI.
$ projports -check -conflicts
PORT STATUS KIND LABEL SOURCE DETAIL
3000 IN USE compose web docker-compose.yml:5 3000:80
3000 IN USE env PORT .env.example:2 PORT=3000
5433 free compose db docker-compose.yml:12 5433:5432
…
Conflicts:
3000: .env.example (env), docker-compose.yml (compose), package.json (script)
What it scans
- Docker Compose short and long port syntax, plus
expose
- Dockerfile
EXPOSE
.env/.env.examplekeys likePORTand*_PORT, and ports inside URLs such asDATABASE_URL
package.jsonscripts (--port,-p,PORT=)- Spring
server.port, common frontend configportfields - Fly.io, Procfile, Vagrant forwarded ports, Kubernetes
containerPort/hostPort/nodePort
- Optional low-confidence README
localhost:PORThits via-low
Why not existing tools?
I looked. Live port managers and kill-port utilities are plentiful and useful once processes are up. Env linters compare keys between files but are not port maps. Compose-only helpers miss the rest of the monorepo. I wanted one command that answers: if I start this project as documented, which host ports does it claim, and do any of them already collide?
Install
go install github.com/SybilGambleyyu/projports@latest
# or
git clone https://github.com/SybilGambleyyu/projports.git
cd projports && go build -o projports .
Honest limits
- Not a remote network scanner and not a security tool.
- Does not (yet) resolve the PID/command holding a live port — use
lsof/ssfor that. - Frontend configs are matched with practical patterns, not a full JS AST, so exotic setups may be missed.
If it saves you a round of "why is 3000 taken?" after clone day, it's done its job. Issues and improvements welcome on the repo.