GitHub - vercel-labs/portless: Replace port numbers with stable, named .localhost URLs. For humans and agents.
Key Points
- 1Portless replaces traditional, fragile port numbers in local development with stable, named `.localhost` URLs, enhancing the experience for both humans and AI agents.
- 2It functions via a central proxy that automatically assigns free ports to applications and routes traffic from unique `.localhost` domains to their respective services.
- 3This system resolves common development issues such as port conflicts, cookie clashes, and hardcoded ports, further offering HTTP/2 and HTTPS support with automatic certificate management.
Portless is a developer tool designed to replace ephemeral, numerical port assignments for local development servers with stable, human-readable, and agent-friendly .localhost URLs. Its primary goal is to resolve common pain points associated with traditional local development, particularly in environments with multiple services or monorepos.
The core problem addressed by Portless is the fragility of local development using hardcoded or dynamically assigned port numbers. This includes issues such as EADDRINUSE port conflicts, the cognitive load of memorizing which service runs on which port, browser tab confusion when different applications subsequently occupy the same port, and the compounding effect of these problems in monorepo setups. Furthermore, it tackles challenges with AI coding agents guessing incorrect ports, cookie and localStorage clashes across applications on localhost, broken hardcoded configurations (e.g., CORS allowlists, OAuth redirect URIs), difficulty sharing development URLs, and the lack of meaningful browser history for localhost entries.
Portless fixes these issues by introducing a central proxy and assigning stable, named .localhost URLs to each application. The methodology operates as follows:
- Central Proxy: A single
portless proxyruns on a designated port (defaulting to 1355), serving as the entry point for all*.localhosttraffic. This proxy can be started explicitly usingportless proxy startor is automatically initiated when an application is registered. For ports below 1024 (e.g., port 80),sudois required. - Application Registration: When an application is launched via , Portless internally assigns a free, random ephemeral port (typically within the 4000-4999 range) to that application. It then registers this and its corresponding ephemeral port with the central
portlessproxy. - Environment Variable Injection: For most modern frameworks (Next.js, Express, Nuxt), Portless passes the assigned port and host via standard
PORTandHOSTenvironment variables. For frameworks that do not inherently respect these (e.g., Vite, Astro, React Router, Angular), Portless intelligently auto-injects the necessary--portand--hostcommand-line flags directly into the executedcommand. - Proxy-Based Routing: When a browser or agent requests , the request is routed through the
portlessproxy. The proxy, based on its internal mapping, then forwards the request to the specific ephemeral port where themyappapplication is actually running. This provides a stable, named entry point while allowing the underlying application to run on any available port.
Key features and functionalities include:
- HTTPS/HTTP/2 Support: Portless can enable HTTPS and HTTP/2 for dev servers. This is activated with
portless proxy start --https, which automatically generates and trusts a local CA (requiring a one-timesudoprompt to add to the system trust store). Custom certificates can also be used via--certand--keyflags. The environment variable makes HTTPS the default. HTTP/2 improves performance by multiplexing requests, mitigating HTTP/1.1's 6-connection limit, which is beneficial for unbundled dev servers. - Command-Line Interface (CLI):
- : Runs an application and maps it to .
portless list: Displays all currently active routes and their mapped ports.portless trust: Manually adds the local CA to the system trust store.portless proxy start: Explicitly starts the daemonized proxy.portless proxy stop: Stops the proxy.
- Disabling Portless: The or environment variables can temporarily bypass Portless, allowing commands to run directly on their default ports.
- State Management: Portless stores its state (routes, PID, port file) in a directory that varies based on the proxy port. For ports < 1024 (requiring sudo), state is shared in
/tmp/portless. For ports >= 1024, it's user-scoped in~/.portless. The state directory can be overridden withPORTLESS_STATE_DIR. - Inter-App Proxying: When one Portless-managed frontend (e.g., Vite, webpack) proxies API requests to another Portless-managed backend service (e.g.,
api.myapp.localhost:1355), it is critical to configure the frontend's proxy to rewrite theHostheader. This is achieved by settingchangeOrigin: truein the proxy configuration. Failure to do so results in theHostheader of the original frontend being sent to the backend, causing the Portless proxy to route the request back to the frontend in an infinite loop, which Portless detects and responds with a508 Loop Detectederror.
Portless requires Node.js 20+ and runs on macOS or Linux operating systems.