Bind 2 Port 0

Port conflicts for local environments are largely a convention failure. The OS has a port allocator. Bind to port 0, ask the server which port it was allocated, and the majority of EADDRINUSE errors disappear.

Default static ports are (now) a silly convention. Worktrees and agents need parallel local environments that don't collide. Port conflicts (mostly) disappear if you stop defaulting to a hardcoded value.

The fix

  1. Default your services on port 0.
  2. Query each bound socket for its assigned port.
  3. Pass those addresses to anything that depends on them.

Orchestrate with real addresses instead of configs. If you can't for whatever reason, you can wrap it with a utility. [1]

Bind to nothing static

Broadly speaking, the same principle extends to database names, temp directories, lockfiles, and socket paths. Anything where two environments might collide. If a resource identifier is hardcoded, it's a serialization point. Let the system assign it, then publish the result.

[1]: Here's a lil b2p0 utility for illustration:

require "socket"
def with_ports(count)
servers = count.times.map { TCPServer.new("127.0.0.1", 0) }
yield servers.map { |s| s.addr[1] }
ensure
servers&.each(&:close)
end
with_ports(3) do |redis_port, api_port, web_port|
# Three services, zero collisions, zero configuration
end

An atomically correct version would utilize file-descriptors, require framework coordination, a longer blog, and would likely be more interesting. But, this snippet is good enough for local environments.