Port Selector
Use port-selector instead of hard-coded ports or hand-written lsof loops. Allocate from the same working directory in which the service runs because allocations are stable per (directory, name).
Start a local service
- Confirm the CLI is available with
command -v port-selector. If it is missing, install it with the repository's documented method before continuing. - Choose a short stable service name such as
web,api,docs,preview, ore2e. Use different names for services that run concurrently from the same directory. - Allocate and start the process in one shell command. Quote the port variable.
PORT="$(port-selector --name preview)"
python3 -m http.server "$PORT"
Adapt how the port is passed to the program:
# Program reads PORT from the environment
PORT="$(port-selector --name web)" npm run dev
# Program accepts a port flag
PORT="$(port-selector --name web)"
npm run dev -- --port "$PORT"
# Playwright or another consumer needs a base URL
PORT="$(port-selector --name e2e)"
BASE_URL="http://127.0.0.1:$PORT" npx playwright test
For a later shell call, run port-selector --name <name> again from the same directory instead of copying a port number from prior output. It returns the stable allocation.
Verify before using
Wait for the service to report readiness or probe its expected endpoint on the allocated port. Do not assume that process startup means the listener is ready.
PORT="$(port-selector --name preview)"
curl --fail --silent --show-error "http://127.0.0.1:$PORT/" >/dev/null
If the expected service is already responding, reuse it instead of starting a duplicate process. Use port-selector --list or port-selector --verbose --name <name> when allocation ownership is unclear.
Recover from a bind conflict
Never kill or replace an unknown listener merely to claim its port.
If startup fails with EADDRINUSE, Address already in use, or an equivalent bind error:
- Stop and reuse the existing process if it is the intended service.
- Otherwise remove only this directory's named allocation:
port-selector --forget --name preview
- Allocate again with the same name and retry startup once.
- If the retry also fails, inspect
port-selector --listand report the conflict rather than starting an unbounded port scan.
Do not use --forget-all, --force, or terminate another process unless the user explicitly authorizes the broader action.
Long-running and parallel work
- Keep the allocation after stopping a normal service so the project retains a predictable port.
- Use
port-selector --lock --name <name>only when a port must remain reserved for a long-running service; unlock it when that reservation ends. - Use separate names for
web,api, databases, documentation, and test servers in the same directory. - Let separate worktrees allocate from their own directories; do not copy one worktree's port into another.
- Prefer
127.0.0.1for local verification unless the service requires a different bind address.