Port Manager for Development Environments
Project description
Portman
Port Manager for Development Environments
Portman automatically manages port allocations across multiple git worktrees and development contexts, preventing port conflicts when running Docker services.
The Problem
When working on multiple branches or worktrees of the same project, Docker services (PostgreSQL, Redis, etc.) conflict on ports. You end up manually managing port assignments, which is error-prone and time-consuming.
Example: Running PostgreSQL on port 5432 in worktree A crashes when you start the same service in worktree B.
The Solution
Portman provides:
- Automatic port allocation - Each worktree gets unique ports
- Machine-wide uniqueness - No conflicts across any projects
- Context-aware - Automatically detects your project and branch
- direnv integration - Ports are automatically available as environment variables
- Docker Compose discovery - Auto-detects services from
docker-compose.yml - Zero configuration - Works out of the box
Installation
Using uv (recommended)
uv tool install portman-cli
Using pip
pip install portman-cli
From source
git clone https://github.com/jpoutrin/portman-cli.git
cd portman-cli
uv pip install -e .
Quick Start
1. Basic Usage
Book a port for a service in your current worktree:
portman book postgres
Get the allocated port:
portman get postgres
# Output: 5432
2. Auto-discovery from docker-compose.yml
If you have a docker-compose.yml file, Portman can automatically discover and book ports for all services:
portman book --auto
This scans your docker-compose.yml and allocates ports for each service.
For custom compose file names:
portman book --auto --compose-file docker-compose.prod.yml
3. direnv Integration (Recommended)
Add to your .envrc:
eval "$(portman export --auto)"
Then allow direnv:
direnv allow
Now your environment variables are automatically set:
echo $POSTGRES_PORT
# Output: 5432
echo $REDIS_PORT
# Output: 6379
When you switch worktrees, the ports change automatically!
Common Workflows
Working with Multiple Worktrees
# In worktree main
cd ~/projects/myapp-main
portman book postgres
portman get postgres
# Output: 5432
# In worktree feature
cd ~/projects/myapp-feature
portman book postgres
portman get postgres
# Output: 5433 (different port, no conflict!)
Using with Docker Compose
Update your docker-compose.yml to use environment variables:
services:
postgres:
image: postgres:15
ports:
- "${POSTGRES_PORT:-5432}:5432"
redis:
image: redis:7
ports:
- "${REDIS_PORT:-6379}:6379"
Then in your .envrc:
eval "$(portman export --auto)"
For custom compose files:
eval "$(portman export --auto --compose-file docker-compose.prod.yml)"
Working with Multiple Compose Files
If your project uses different compose files for different environments:
# Development environment
portman book --auto --compose-file docker-compose.dev.yml
# Production environment
portman book --auto --compose-file docker-compose.prod.yml
# Staging environment
portman book --auto --compose-file compose.staging.yaml
The --compose-file option works with both relative and absolute paths.
Manual Port Allocation
Prefer a specific port:
portman book postgres --port 5555
Book multiple services:
portman book postgres
portman book redis
portman book mongodb
List All Allocations
See all port allocations across all contexts:
portman list
See allocations for the current context only:
portman list --current
Clean Up
Release a specific service in the current context:
portman release postgres
Release all ports for the current context:
portman release --all
Remove allocations for deleted worktrees:
portman prune
Remove stale allocations (not accessed in 30 days):
portman prune --stale 30
Commands Reference
portman book
Book a port for a service.
# Book with auto-assigned port
portman book <service>
# Book with preferred port
portman book <service> --port <port>
# Auto-discover from docker-compose.yml
portman book --auto
# Auto-discover from custom compose file
portman book --auto --compose-file docker-compose.prod.yml
portman book --auto -f compose.staging.yaml
portman get
Get the allocated port for a service (for scripting).
portman get <service>
# With quiet output (just the port number)
portman get <service> --quiet
portman export
Export environment variables for direnv.
# Manual services
portman export postgres redis
# Auto-discover from docker-compose.yml
portman export --auto
# Auto-discover from custom compose file
portman export --auto --compose-file docker-compose.prod.yml
# With custom format
portman export postgres --format "POSTGRES_URL=postgresql://localhost:{port}/db"
portman list
List all port allocations.
# All contexts
portman list
# Current context only
portman list --current
# Show system ports
portman list --system
portman release
Release port allocations.
# Release specific service
portman release <service>
# Release all in current context
portman release --all
portman prune
Clean up orphaned or stale allocations.
# Dry run (show what would be removed)
portman prune --dry-run
# Remove orphaned allocations
portman prune
# Remove allocations not accessed in N days
portman prune --stale 30
# Force without confirmation
portman prune --force
portman init
Initialize direnv integration.
# Add export to .envrc
portman init
# Just show the command
portman init --print
portman config
Manage port ranges.
# Show current configuration
portman config --show
# Set port range for a service
portman config --set-range postgres:5400-5500
portman status
Show system information and diagnostics.
portman status
portman discover
Discover services from docker-compose files without booking them.
# Discover from standard compose files
portman discover
# Discover from custom compose file
portman discover --compose-file docker-compose.prod.yml
portman discover -f compose.staging.yaml
Shows what services would be booked with portman book --auto.
How It Works
- Context Detection: Portman generates a unique hash based on your project path and git worktree
- Database: Port allocations are stored in a SQLite database at
~/.local/share/portman/allocations.db - Port Allocation:
- Checks if port is already allocated for this context
- Scans system for ports in use
- Allocates from service-specific ranges (e.g., 5432-5532 for PostgreSQL)
- Guarantees machine-wide uniqueness
- direnv Integration: Exports environment variables that update automatically when you switch directories
Configuration
Port ranges are configurable per service. Default ranges:
- PostgreSQL: 5432-5532
- Redis: 6379-6479
- MongoDB: 27017-27117
- MySQL: 3306-3406
Set custom ranges:
portman config --set-range postgres:5400-5500
Requirements
- Python 3.10 or higher
- Git (for context detection)
- direnv (optional, for automatic environment variable management)
License
MIT
Contributing
Contributions are welcome! Please open an issue or pull request on GitHub.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file portman_cli-1.1.0.tar.gz.
File metadata
- Download URL: portman_cli-1.1.0.tar.gz
- Upload date:
- Size: 64.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
31ab93a1d362178ac6a2ac2c1d8df7dc9140905b2f29ca07d4674e1b064fdbac
|
|
| MD5 |
e0e048c1ca1607953424b1556fef4408
|
|
| BLAKE2b-256 |
e9909a415e43720f6fd416817e9dc6543a8b530f44c1375899be07f06642c6a8
|
Provenance
The following attestation bundles were made for portman_cli-1.1.0.tar.gz:
Publisher:
release.yml on jpoutrin/portman-cli
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
portman_cli-1.1.0.tar.gz -
Subject digest:
31ab93a1d362178ac6a2ac2c1d8df7dc9140905b2f29ca07d4674e1b064fdbac - Sigstore transparency entry: 725648655
- Sigstore integration time:
-
Permalink:
jpoutrin/portman-cli@13946f2cfe746a65db477093228be0f86907c3bb -
Branch / Tag:
refs/tags/v1.1.0 - Owner: https://github.com/jpoutrin
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@13946f2cfe746a65db477093228be0f86907c3bb -
Trigger Event:
push
-
Statement type:
File details
Details for the file portman_cli-1.1.0-py3-none-any.whl.
File metadata
- Download URL: portman_cli-1.1.0-py3-none-any.whl
- Upload date:
- Size: 20.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1cb077adfe1291e74b2588944da6b6e85c5da4d9877a51bbb6b92e0eaa58d7ed
|
|
| MD5 |
5062c131cfbbc1d32ec7c8d728814ece
|
|
| BLAKE2b-256 |
9d77e1eb047190c0eb5fbc36771a73adf8d92fcef003bb9ed882a1d8030b243d
|
Provenance
The following attestation bundles were made for portman_cli-1.1.0-py3-none-any.whl:
Publisher:
release.yml on jpoutrin/portman-cli
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
portman_cli-1.1.0-py3-none-any.whl -
Subject digest:
1cb077adfe1291e74b2588944da6b6e85c5da4d9877a51bbb6b92e0eaa58d7ed - Sigstore transparency entry: 725648670
- Sigstore integration time:
-
Permalink:
jpoutrin/portman-cli@13946f2cfe746a65db477093228be0f86907c3bb -
Branch / Tag:
refs/tags/v1.1.0 - Owner: https://github.com/jpoutrin
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@13946f2cfe746a65db477093228be0f86907c3bb -
Trigger Event:
push
-
Statement type: