Zurück zum Journal
portlessdevtoolslocalhostvercelentwicklungmonorepo

Portless: Nie wieder Port-Nummern merken

Statt localhost:3000, :8080, :5173 – mit portless bekommt jeder Dev-Server einen stabilen Namen. Ein CLI-Tool von Vercel, das Localhost aufräumt.

Portless: Nie wieder Port-Nummern merken

Jeder Entwickler kennt das: Du startest drei Projekte nebeneinander, und plötzlich merkst du nicht mehr, ob die API auf :3001 oder :8080 lief. Oder zwei Projekte wollen denselben Port, und alles bricht mit EADDRINUSE ab. Cookies auf localhost überschneiden sich, Browser-Verlauf wird zu einem Chaos.

Portless

Was ist Portless?

Portless ist ein CLI-Tool (von Vercel, aktuell v0.13, pre-1.0), das Port-Nummern durch benannte .localhost-URLs ersetzt. Statt http://localhost:3000 heißt dein Dev-Server dann einfach https://myapp.localhost – mit echtem HTTPS und HTTP/2.

diff
- "dev": "next dev"                  # http://localhost:3000
+ "dev": "portless myapp next dev"   # https://myapp.localhost

Das ist kein Proxy-Manager im Stil von Traefik oder nginx. Portless ist explizit für den lokalen Entwicklungs-Workflow gebaut – schnell eingerichtet, kein Docker, kein Config-Overhead.

Installation und erster Start

Global installieren (empfohlen):

bash
npm install -g portless

Oder als Projektabhängigkeit:

bash
npm install -D portless

Dann reicht ein einfaches portless im Projektverzeichnis. Das Tool liest automatisch den "dev"-Script aus der package.json, leitet den App-Namen vom Package-Namen, Git-Root oder Verzeichnisnamen ab und startet den Proxy:

bash
portless
# -> Liest "dev" aus package.json, startet https://<project>.localhost

HTTPS mit HTTP/2 ist standardmäßig aktiviert. Beim ersten Run generiert Portless eine lokale CA, vertraut sie und bindet Port 443. Mit --no-tls schaltest du auf plain HTTP um.

Warum das besser ist als Port-Nummern

Portless nennt sieben konkrete Schmerzpunkte, die jeder kennt, der mit mehreren Dev-Servern arbeitet:

  • Port-Konflikte: Zwei Projekte auf demselben Port? Mit Portless bekommt jede App automatisch einen eigenen Port hinter ihrem Namen. Kein EADDRINUSE mehr.
  • Port-Merk-Aufwand: War die API auf 3001 oder 8080? Mit Portless ist sie immer https://api.localhost.
  • Falsche App nach Refresh: Einen Server gestoppt, einen anderen auf demselben Port gestartet – und der Browser-Tab zeigt plötzlich etwas Komplett anderes. Benannte URLs eliminieren das.
  • Cookie- und Storage-Kollisionen: Cookies auf localhost gelten für alle Ports. localStorage geht verloren, wenn sich Ports ändern. Jede .localhost-Subdomain bekommt ihren eigenen Scope.
  • Hardcodierte Ports in Config: CORS-Allowlists, OAuth-Redirect-URIs, .env-Dateien – alles bricht, wenn sich Ports ändern. Mit Portless sind URLs stabil.
  • Browser-Verwirrung: Dein Verlauf für localhost:3000 ist ein Mix aus fünf Projekten. Benannte URLs trennen das sauber.
  • KI-Agenten am falschen Port: AI-Coding-Agenten erraten oder hardcodieren Ports – besonders in Monorepos ein Problem. Eine stabile URL wie https://myapp.localhost ist deterministisch und zuverlässig.

Subdomains für Microservices

Das ist der Punkt, wo Portless für mich richtig interessant wird. In einem Setup mit Frontend, API und Docs reicht:

bash
portless api.myapp pnpm start   # -> https://api.myapp.localhost
portless docs.myapp next dev    # -> https://docs.myapp.localhost

Jeder Service bekommt seinen eigenen Namen, seinen eigenen Scope, seine eigenen Cookies. Ohne Config-Datei, ohne Port-Mapping.

Git Worktrees ohne Kollisionen

Wer mit Git-Worktrees arbeitet, kennt das Problem: Zwei Branches desselben Projekts können nicht denselben Port nutzen. Portless erkennt Worktrees automatisch und prepended den Branch-Namen als Subdomain:

bash
# Main-Worktree
portless run next dev   # -> https://myapp.localhost

# Linked Worktree auf Branch "fix-ui"
portless run next dev   # -> https://fix-ui.myapp.localhost

Keine Kollisionen, kein --force. Einmal in package.json eintragen, überall funktionsfähig.

Monorepo-Support

Portless erkennt Monorepo-Strukturen (pnpm, npm, yarn, bun) und startet automatisch alle Workspace-Packages mit einem "dev"-Script:

bash
portless   # im Monorepo-Root: startet alle Apps

Jedes Package bekommt eine Subdomain nach dem Muster <package>.<project>.localhost. Wenn Turborepo erkannt wird, delegiert Portless an turbo run und behält die Dependency-Orchestrierung bei. Eine portless.json im Root erlaubt Overrides pro App:

json
{
  "apps": {
    "apps/web": { "name": "myapp" },
    "apps/api": { "name": "api.myapp" }
  }
}

Docker-Services einbinden

Mit portless alias registrierst du Services, die nicht von Portless verwaltet werden – zum Beispiel einen Docker-Container:

bash
portless alias my-postgres 5432   # -> https://my-postgres.localhost
portless alias redis 6379        # -> https://redis.localhost

Aliase überleben den Stale-Route-Cleanup und bleiben persistent.

Weiteres: Tailscale, Custom TLD, OS-Service

  • Tailscale-Sharing: Mit --tailscale teilt man jede App im Tailscale-Netzwerk. Mit --funnel sogar öffentlich im Internet.
  • Custom TLD: Wer .test statt .localhost bevorzugt: portless proxy start --tld test. Empfohlen: .test (IANA-reserved). Vermeiden: .local (mDNS-Konflikt) und .dev (Google-owned, HSTS).
  • OS-Startup-Service: portless service install richtet einen Systemd/Launchd/Task-Scheduler-Dienst ein, der den Proxy nach Reboot automatisch startet.

Wie es funktioniert

Portless betreibt einen HTTPS-Reverse-Proxy auf Port 443. Jede App registriert eine Route, die ihren Hostnamen auf einen zugewiesenen Port mappt. Requests an https://<name>.localhost werden an die App weitergeleitet.

Der Proxy startet automatisch. Ein zufälliger Port (4000-4999) wird über die PORT-Umgebungsvariable zugewiesen. Die meisten Frameworks (Next.js, Express, Nuxt) respektieren diese automatisch. Bei Frameworks, die PORT ignorieren (Vite, Astro, React Router, Angular), injiziert Portless automatisch den passenden --port- und --host-Flag.

Für wen lohnt sich das?

Portless ist nicht für das kleine Nebenprojekt mit einem Dev-Server gedacht. Aber sobald:

  • du regelmäßig mehrere Services gleichzeitig entwickelst,
  • du in einem Monorepo arbeitest,
  • du Git-Worktrees nutzt,
  • oder KI-Agenten deine Dev-Server ansprechen sollen –

dann lohnt sich der Umstieg sofort. Die Installation dauert eine Minute, der Workflow-Gewinn ist spürbar.

Meine Einschätzung

Portless löst ein echtes Problem, das jeder Entwickler mit mehr als einem lokalen Service kennt. Das Tool ist noch pre-1.0 – die API kann sich ändern, und bei projektlokaler Installation können Versionsskew-Probleme zwischen Teammitgliedern entstehen. Aber der Ansatz ist überzeugend: Weg von Port-Nummern, hin zu benannten URLs.

Besonders die Kombination aus Git-Worktree-Support, Monorepo-Orchestrierung und Docker-Aliasen macht Portless zu einem Werkzeug, das den lokalen Entwicklungsalltag nachhaltig vereinfacht. Und dass HTTPS mit HTTP/2 out-of-the-box funktioniert, ist kein Luxus, sondern eine Notwendigkeit für moderne Browser-APIs (Service Workers, COEP, etc.).

Ich werde Portless in meinem Setup testen – und berichten.