Skip to content
Back to skills

Local Dev Port Management

ASecurity

Design and document a port assignment strategy for local development environments. Use when setting up new projects, resolving port conflicts, or establishing team conventions for port usage across services.

  • 8 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 20, 2026
developmentgojavabashsqlreactnodeexpressflaskkubernetesdebugging

Works with

  • cli
  • api

Security analysis

A100/100

Scanned September 20, 2026

npx -y skills add tstapler/dotfiles --skill local-dev-port-management --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Local Dev Port Management?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Local Dev Port Management
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tstapler-local-dev-port-management/badge)](https://www.skillsdirectory.com/skills/tstapler-local-dev-port-management)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: local-dev-port-management
description: Design and document a port assignment strategy for local development environments. Use when setting up new projects, resolving port conflicts, or establishing team conventions for port usage across services.
---

# Local Dev Port Management

Apply this skill when choosing, documenting, or fixing port assignments for local development services.

## IANA Port Ranges (the foundation)

| Range | Numbers | Rules |
|---|---|---|
| System / Well-Known | 0–1023 | Requires root on Unix. Reserved for OS/standard protocols. Avoid entirely in dev. |
| Registered / User | 1024–49151 | Where all dev tools live. IANA-assigned defaults cluster here. |
| Dynamic / Ephemeral | 49152–65535 | OS assigns these temporarily for client connections. Linux default: 32768–60999 (readable from `/proc/sys/net/ipv4/ip_local_port_range`). **Never hardcode services here** — the OS will steal them on restart. |

## Common Tool Defaults (memorise to avoid collisions)

| Port | Service |
|---|---|
| 3000 | Express, React (CRA), many Node tools |
| 4000 | Firebase Emulator UI |
| 5000 | Firebase Hosting emulator, Overmind/Hivemind base port, Flask (Linux) |
| 5001 | Firebase Functions emulator, Flask (macOS since 2.3+) |
| 5002 | Firebase App Hosting emulator |
| 5173 | Vite dev server |
| 5432 | PostgreSQL |
| 6379 | Redis |
| 8080 | Firebase Firestore emulator, generic HTTP alternative |
| 8085 | Firebase Pub/Sub emulator |
| 9000 | Firebase Realtime Database emulator |
| 9099 | Firebase Auth emulator |
| 9199 | Firebase Cloud Storage emulator |
| 9229 | Node.js inspector (debugger) |
| 27017 | MongoDB |

## Conflict Avoidance Strategies

### 1. Explicit declaration in gradle.properties / .env (recommended default)
Define all ports centrally. Every service reads from that file. Zero runtime magic.

```properties
# gradle.properties (Gradle projects)
webApp.devPort=3001
firebase.emulator.firestore=9090
firebase.emulator.auth=9099

# .env (Node/general)
WEB_PORT=3001
API_PORT=3002
DB_PORT=5432
```

**Rule**: Firestore emulator should NOT be on 8080 — webpack, most HTTP servers, and Java app servers all default there. Move it to 9090.

### 2. Per-project port ranges (namespace by project)
Assign each project a 100-port block in the registered range. Document in a team wiki.

```
Project A: 3100–3199  (web: 3100, api: 3101, db proxy: 3102)
Project B: 3200–3299
Project C: 3300–3399
```

Tools like Overmind/Hivemind automate this: they assign `BASE + (process_index × STEP)` and inject `PORT` env var into each process.

### 3. Procfile process managers (Overmind / Hivemind)
Both tools read a `Procfile`, start each process, and assign ports sequentially:

```
# Procfile
web: ./gradlew :webApp:wasmJsBrowserDevelopmentRun
api: ./gradlew :cliApp:run
```

```bash
# Overmind — start all with base port 3000, step 100
PORT=3000 overmind start
# web gets 3000, api gets 3100
# Each process also sees OVERMIND_PROCESS_<name>_PORT for siblings
```

Overmind is preferred over Hivemind for projects that need process restart control (`overmind restart web`).

### 4. Named subdomains instead of ports (Portless)
[vercel-labs/portless](https://github.com/vercel-labs/portless) replaces port numbers with `.localhost` names:
- `https://web.localhost` instead of `http://localhost:3001`
- Assigns random ports internally (4000–4999 range), exposes them via `PORT` env var
- Best for teams where port numbers keep drifting

### 5. Persistent named port registry (port-for)
[port-for](https://github.com/fizyk/port-for) stores stable name→port bindings in `/etc/port-for.conf`:

```bash
sudo port-for add myapp    # assigns and persists a stable port for "myapp"
port-for show myapp        # always returns same port
```

Survives machine restarts. Avoids ephemeral range collisions by reading the OS range at runtime.

### 6. Service mesh intercept (Telepresence — Kubernetes only)
For services running in Kubernetes, Telepresence routes cluster traffic to your local machine. Local port and cluster port can differ:

```bash
telepresence intercept my-service --port 3001:8080
# local :3001 intercepts cluster :8080 traffic
```

Eliminates port management entirely for remote-dependent services.

## Decision Guide

| Situation | Strategy |
|---|---|
| Solo developer, 1–3 services | `.env` / `gradle.properties` with explicit ports |
| Team project, multiple services per dev | Per-project port ranges documented in wiki |
| Frequently starting/stopping many services | Procfile + Overmind |
| Sick of remembering port numbers | Portless (named subdomains) |
| Stable named ports needed system-wide | port-for |
| Kubernetes microservices dev | Telepresence |

## Sequential Batch Strategy (recommended for projects with multiple services)

**The pattern**: claim a sequential block of N ports from the IANA dynamic range (49152–65535), above the OS ephemeral ceiling.

**Why above the ephemeral ceiling?** On Linux the ephemeral range tops at 60999 by default. Ports 61000–65535 are in the IANA dynamic range but the kernel never assigns them to outbound connections — no `ip_local_reserved_ports` needed. On macOS (ephemeral extends to 65535) you need explicit reservation.

**Algorithm for grabbing a batch:**
1. Read OS ephemeral ceiling: `cat /proc/sys/net/ipv4/ip_local_port_range` (Linux) or `sysctl net.inet.ip.portrange.last` (macOS)
2. Start batch at `ceiling + 1` (Linux: 61000) or reserve via `ip_local_reserved_ports`/sysctl
3. Assign services sequentially from base
4. Check availability: `ss -tlnp | grep -E ':(61000|61001|...)'`
5. Persist reservation if needed (Linux: `/etc/sysctl.d/99-project-ports.conf`, macOS: LaunchDaemon plist)

**Reservation script** (create as `scripts/reserve-ports.sh`):
- Reads OS type + ephemeral range
- Checks batch for conflicts
- Reserves via `ip_local_reserved_ports` (Linux) or narrows ephemeral start (macOS)
- Persists across reboots
- Run with `--check` for dry-run, `--show` for port table

**Picking your base**: anything above your OS ephemeral ceiling works. Simple choices:
- Linux: 61000 (one past default ceiling 60999)
- macOS: 49152 (IANA dynamic start) — but requires reservation
- Cross-platform safe: 61000 + reserve on macOS

## Sortie-Specific Conventions

Sequential batch **64386–64395** — derived from project name, not a round number:

```properties
# gradle.properties — base 64386 = 61000 + CRC32("sortie") % 4525
webApp.devPort=64386
firebase.emulator.ui=64387
firebase.emulator.auth=64388
firebase.emulator.firestore=64389
firebase.emulator.functions=64390
firebase.emulator.hosting=64391
# 64392-64395 spare
```

```json
// firebase.json emulators section
{ "auth": {"port": 61002}, "firestore": {"port": 61003},
  "functions": {"port": 61004}, "hosting": {"port": 61005},
  "ui": {"enabled": true, "port": 61001} }
```

`make reserve-ports` — checks batch availability, reserves on macOS if needed, shows port table.
`make ports` — shows the assignment table without any changes.

## Sources

- [RFC 6335 — IANA Port Assignment](https://www.rfc-editor.org/rfc/rfc6335.html)
- [Firebase Emulator Suite — Install & Configure](https://firebase.google.com/docs/emulator-suite/install_and_configure)
- [Overmind GitHub](https://github.com/DarthSim/overmind)
- [Hivemind GitHub](https://github.com/DarthSim/hivemind)
- [Portless GitHub](https://github.com/vercel-labs/portless)
- [port-for GitHub](https://github.com/fizyk/port-for)
- [Kubernetes local debugging with Telepresence](https://kubernetes.io/docs/tasks/debug/debug-cluster/local-debugging/)

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…