Skip to content

Port Resolver

Concurrent port allocation for any application - avoid port conflicts in tests, servers, microservices, and development.

Overview

Port Resolver (portres) provides a centralized, file-based registry for port allocation. When running tests in parallel or multiple services in development, it ensures each process gets a unique port without conflicts.

Uses semats Library

This tool uses file-based-semaphore-ts as a library dependency for atomic registry access. See PRINCIPLES.md Exception 2 for details on Tuulbelt tool composition.

Status: Production Ready (v0.1.0)

Language: TypeScript

Repository: tuulbelt/port-resolver

Features

File-Based Registry

Centralized port registry with atomic operations. Multiple processes coordinate without conflicts.

Real Port Verification

TCP bind test confirms ports are actually available, not just recorded as free.

Automatic Stale Cleanup

Detects and removes stale entries from crashed processes based on PID checks.

Semaphore-Protected

Uses file-based-semaphore-ts for atomic registry access.

CLI & Library

Use as a command-line tool for shell scripts or integrate as a TypeScript/JavaScript library.

Zero Runtime Dependencies

Uses only Node.js built-ins plus Tuulbelt tools (zero external dependencies maintained).

Quick Start

bash
# Clone the repository
git clone https://github.com/tuulbelt/port-resolver.git
cd port-resolver

# Install dev dependencies
npm install

# CLI usage
portres get --tag "api-server"
# Output: 54321

# Release when done
portres release --port 54321
typescript
// Library usage
import { PortResolver } from '@tuulbelt/port-resolver';

const resolver = new PortResolver();
const result = await resolver.get({ tag: 'my-server' });
if (result.ok) {
  const port = result.value.port; // Guaranteed unique
  // Start your server on this port
}

Demo

See the tool in action:

Port Resolver Demo

▶ View interactive recording on asciinema.org

Try it online:Open in StackBlitz

Use Cases

  • Parallel Test Workers: Running tests with --workers=4 or similar
  • Integration Tests: Tests that spawn servers or databases
  • E2E Tests: Multiple services running simultaneously
  • Development: Multiple microservices in local development
  • CI/CD Pipelines: Avoiding port conflicts in shared runners

Why Port Resolver?

The common problem with hardcoded ports:

Error: listen EADDRINUSE: address already in use :::3000

This happens because:

  • Tests hardcode port numbers (:3000, :8080)
  • Multiple test workers race for the same ports
  • Flaky "works locally, fails in CI" behavior

Port Resolver solves this by providing a centralized registry with atomic operations.

API Overview

MethodDescription
get(config?)Allocate a single port
getMultiple(count, config?)Allocate multiple ports
release(port)Release an allocated port
releaseAll(tag?)Release all ports (optionally by tag)
list()List all allocated ports
clean()Remove stale entries
status()Get registry statistics

Documentation

License

MIT License - see repository for details.

Released under the MIT License.