Commands

Zero-arg mode

portless

Runs the "dev" script from package.json through the proxy. The app name is inferred from the package name, git root, or directory name. From a monorepo root (detected via pnpm-workspace.yaml or package.json "workspaces"), starts all workspace packages that have the target script.

portless                      # single app: run dev script
portless                      # monorepo root: start all apps
portless --script start       # run "start" instead of "dev"

Use a portless.json to override defaults. See Configuration.

Run an app

portless run [--name <name>] [cmd] [args...]
portless <name> <cmd> [args...]

portless run infers the project name from portless.json, package.json, git root, or directory name. When no command is given, runs the configured script (default: "dev") from package.json. Use --name to override the inferred name while still applying worktree prefixes.

portless <name> uses an explicit name with no inference or prefixing.

portless run                             # run dev script through proxy
portless run next dev                    # infer name from project
portless run --name myapp next dev       # override inferred name
portless myapp next dev                  # explicit name
portless api pnpm start
portless docs.myapp next dev
FlagDescription
--name <name>Override the inferred base name (worktree prefix still applies). Only for portless run.
--script <name>Run a specific package.json script instead of the default ("dev"). Global flag.
--app-port <number>Use a fixed port for the app instead of auto-assignment. Also configurable via PORTLESS_APP_PORT or portless.json.
--forceOverride an existing route registered by another process

Get a service URL

portless get <name>

Print the URL for a service. Useful for wiring services together in scripts or env vars:

BACKEND_URL=$(portless get backend)

Applies worktree prefix detection by default. Use --no-worktree to skip it.

Alias (static routes)

portless alias <name> <port>
portless alias <name> <port> --force
portless alias --remove <name>

Register a route for a service not managed by portless (e.g. a Docker container). Aliases persist across stale-route cleanup.

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

List routes

portless list

Shows active routes and their assigned ports.

Trust the CA

portless trust

Adds the portless certificate authority to your system trust store. Required once for HTTPS with auto-generated certs.

Clean up

portless clean

Stops the proxy if it is running, removes the portless CA from the OS trust store when portless installed it, deletes allowlisted files under ~/.portless, the system state directory, and PORTLESS_STATE_DIR when set, and removes the portless block from /etc/hosts. May prompt for elevated privileges. Custom --cert / --key paths are not removed.

Prune orphans

portless prune
portless prune --force

Finds and kills orphaned dev server processes left behind by crashed portless sessions. When the CLI is killed with kill -9 or crashes, child dev servers may survive and continue holding their ports. This command checks routes whose owning process is dead but whose port is still in use, terminates the orphans, and removes the stale route entries. Use --force to send SIGKILL instead of SIGTERM.

Proxy control

Start

portless proxy start
FlagDescription
-p, --port <number>Proxy port (default: 443, or 80 with --no-tls). Auto-elevates with sudo.
--no-tlsDisable HTTPS (use plain HTTP on port 80)
--httpsEnable HTTPS (default, accepted for compatibility)
--lanEnable LAN mode (mDNS .local domains for real device testing)
--ip <address>Override auto-detected LAN IP (use with --lan)
--tld <tld>Use a custom TLD instead of .localhost (e.g. test). Hostnames still sync to /etc/hosts by default.
--cert <path>Custom TLS certificate
--key <path>Custom TLS private key
--foregroundRun in foreground instead of daemon mode

Stop

portless proxy stop

OS startup service

portless service install
portless service status
portless service uninstall

Installs the proxy as an OS startup service using the default clean URL behavior: HTTPS on port 443 with .localhost names. macOS and Linux use a root-owned service so port 443 can bind at boot. Windows uses a Task Scheduler startup task that runs as SYSTEM. Installation and removal may require administrator privileges. portless clean automatically removes the service.

LAN mode

Access services from phones and other devices on the same WiFi via mDNS (.local domains):

portless proxy start --lan
portless proxy start --lan --https
portless proxy start --lan --ip 192.168.1.42   # manual IP override

Make it permanent by adding export PORTLESS_LAN=1 to your shell profile. Portless also remembers LAN mode via proxy.lan, so a stopped LAN proxy starts in LAN mode again unless you override it with PORTLESS_LAN=0 for that start.

Uses dns-sd on macOS (built-in) and avahi-publish-address on Linux (avahi-utils). Not supported on Windows.

Framework notes:

  • Next.js: Add allowedDevOrigins: ['myapp.local', '*.myapp.local'] to next.config.js so LAN mode requests still work when portless adds a git worktree prefix.
  • Vite / React Router / SvelteKit / Astro: Handled automatically via __VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS.
  • Expo / React Native: Add NSAllowsLocalNetworking to your app.json for iOS ATS (see Getting Started for the .localhost equivalent using NSExceptionDomains):
{
  "expo": {
    "ios": {
      "infoPlist": {
        "NSAppTransportSecurity": {
          "NSAllowsLocalNetworking": true
        }
      }
    }
  }
}

Hosts

portless hosts sync     # add current routes to /etc/hosts
portless hosts clean    # remove portless entries from /etc/hosts

Auto-sync is on by default. Set PORTLESS_SYNC_HOSTS=0 to disable.

Bypass portless

PORTLESS=0 pnpm dev

Runs the command directly without the proxy.

Info

portless --help
portless --version