Ports are coordinates. Names are handles.
Vercel Labs’ Portless is trending on GitHub today with a tight proposition: run a local app behind a stable https://name.localhost address while an internal proxy assigns the child process a free port. Its README says the default pool is 4000–4999, HTTPS and HTTP/2 are on by default, and common frameworks receive the right port or host flags when the wrapper can classify the command safely.
That sounds cosmetic until the repo contains a frontend, API, docs server, three worktrees, browser tests, OAuth callbacks, and an agent that has to take screenshots after every patch. Numbers describe where processes happened to land. Names describe what they are.
A stable local URL is a tiny piece of infrastructure with an outsized effect on attention.
Do not erase the browser’s real boundary.
MDN’s definition is the brake pedal: an origin is the URL’s scheme, hostname, and port. Change any one and you changed the origin. Replacing explicit ports with hostnames does not abolish browser security; it moves the visible seam. api.myapp.localhost and myapp.localhost are legible service identities, but they are still different hosts.
That can be exactly what you want. It makes cookie scope, CORS behavior, OAuth callbacks, and host-based routing easier to discuss. But “clean URL” must not become “same trust zone.” Name the boundary so the team can reason about it.
The mature move is identity plus exposure.
GitHub Codespaces already treats ports as managed cockpit objects. Its docs explain that printed localhost URLs can be forwarded automatically, converted into clickable links in the browser or VS Code, labeled, configured, and shared at different visibility levels. The lesson is not that one workflow beats another. It is that a preview endpoint needs metadata beyond its integer.
Portless keeps normal mode on IPv4 and IPv6 loopback according to its README; LAN mode is an explicit separate path. That default matters. A friendlier name should not quietly become a wider listener.
Worktrees make the case for names.
The sharpest Portless feature is automatic worktree identity. A linked worktree on branch fix-ui can become https://fix-ui.myapp.localhost while the main checkout keeps the plain name. That turns “which 3000 is this?” into a URL that carries branch context.
For agent-heavy work, that is not garnish. Parallel changes need parallel previews, and every screenshot, callback, console trace, and test receipt should point to the correct branch. Stable names make the evidence easier to bind to the work that produced it.
Install the switchyard, not just the package.
- Name by role. Prefer
app,api.app, anddocs.appover clever hostnames nobody can predict. - Keep branch identity. Let worktrees carry explicit prefixes; print the URL in every preview receipt.
- Record origin assumptions. Scheme, host, cookie scope, callback URL, and CORS policy belong in the same review.
- Separate loopback from sharing. LAN, tunnel, organization, and public visibility are deployment decisions, not URL styling.
- Preserve an escape lane. Portless is pre-1.0 by its own README. Keep the underlying dev command runnable and pin the version when the whole team depends on state or trust-store behavior.
The glow-up is not :3000 versus .localhost. It is accidental coordinates versus inspectable identity. The name wins only when it carries enough context to stop the next human—or agent—from connecting the wrong hose.