Skip to main content

Overview

Static routes let you register a persistent mapping from a .localhost name to a port without starting a process through portless. This is useful for:
  • Docker containers
  • Services started outside portless
  • Long-running background processes
  • External databases or tools
  • Services that don’t accept PORT environment variable
Unlike portless run or portless <name> <command>, static routes don’t launch a child process - they just register a route in the proxy.

Quick Start

The alias Command

Basic Usage

1

Start your service

Start your service on a specific port:
2

Register the route

Create a static route:
3

Access via portless

Access your service via the registered name:

Command Reference

Use Cases

Docker Containers

Register Docker containers by their published port:
Use Docker port mapping (-p host:container) to publish the container’s port to localhost, then register that port with portless.

Multiple Docker Services

Existing Development Server

If you have a server already running that doesn’t use the PORT environment variable:

Background Services

Register long-running services that you start manually:

Third-Party Tools

Register dev tools with UIs:

Docker Compose Integration

Use static routes with Docker Compose:

Overwriting Routes

Force Flag

By default, portless alias fails if a route is already registered:
Use --force to overwrite:
Using --force will disconnect any active connections to the old route. The new route takes effect immediately.

Conflict Behavior

When a route conflict occurs, portless checks if the owning process is still alive:
  1. Process is dead - Route is overwritten automatically (no --force needed)
  2. Process is alive - Requires --force to overwrite
  3. Static route (PID 0) - Requires --force to overwrite
This prevents accidental overwrites while cleaning up stale routes automatically.

Removing Routes

Removing a route doesn’t stop the underlying service - it only removes the proxy mapping. The service continues running on its original port.

Combining with Dynamic Routes

You can mix static routes with dynamic portless run routes:

State Persistence

Static routes are stored in the routes file alongside dynamic routes:
~/.portless/routes.json
  • Static routes have "pid": 0
  • Dynamic routes have a real PID
When the proxy restarts, static routes persist. Dynamic routes are cleaned up if the process is no longer running.

State Directory

Routes are stored based on proxy port:
  • Port >= 1024: ~/.portless/routes.json
  • Port < 1024 (sudo): /tmp/portless/routes.json
Override with:

Wildcard Routing with Static Routes

Static routes support wildcard routing just like dynamic routes:
Your service receives the full Host header and can route internally based on the subdomain.

Real-World Workflows

Microservices Development

Full-Stack with Docker

Monorepo Development

Listing Routes

View all routes (both static and dynamic):
Example output:
Static routes are marked with (static) or (PID 0). Dynamic routes show the managing process PID.

Troubleshooting

Route Registered But Connection Refused

The route is registered, but the service isn’t running on the target port:
Make sure your service is running before accessing the route.

Port Already in Use

If the port you want to use is taken:

Route Conflict

If you see “already registered” errors:

Service Not Receiving Requests

Make sure your service is:
  1. Listening on the correct port
  2. Binding to 127.0.0.1 or 0.0.0.0 (not just localhost in some configurations)
  3. Not behind another proxy that might interfere
Test directly:
If that works, the portless route should work too.

Limitations

No Process Management

Static routes don’t manage the lifecycle of the target service. You’re responsible for:
  • Starting the service
  • Stopping the service
  • Restarting on crashes
  • Ensuring it’s listening on the correct port
For managed processes, use portless run or portless <name> <command> instead.

No Automatic Port Assignment

Unlike dynamic routes, static routes require you to specify the port manually. There’s no auto-assignment.

Stale Routes

If you register a static route but later stop the service without removing the route, the route remains registered. Requests will fail with “connection refused”. Clean up manually:

Comparison: Static vs Dynamic Routes

Reserved Names

These names are reserved for portless subcommands and cannot be used directly:
  • run
  • alias
  • hosts
  • list
  • trust
  • proxy
Workaround:
Or choose a different name:
For most use cases, avoid reserved names. If you must use one, use the --name flag to explicitly force it.