portless
Set up and use portless for named local dev server URLs (e.g. https://myapp.localhost instead of http://localhost:3000). Use when integrating portless into a project, configuring dev server names, setting up the local proxy, working with .localhost domains, or troubleshooting port/proxy issues.
What this skill does
# Portless
Replace port numbers with stable, named .localhost URLs. For humans and agents.
## Why portless
- **Port conflicts**: `EADDRINUSE` when two projects default to the same port
- **Memorizing ports**: which app is on 3001 vs 8080?
- **Refreshing shows the wrong app**: stop one server, start another on the same port, stale tab shows wrong content
- **Monorepo multiplier**: every problem scales with each service in the repo
- **Agents test the wrong port**: AI agents guess or hardcode the wrong port
- **Cookie/storage clashes**: cookies on `localhost` bleed across apps; localStorage lost when ports shift
- **Hardcoded ports in config**: CORS allowlists, OAuth redirects, `.env` files break when ports change
- **Sharing URLs with teammates**: "what port is that on?" becomes a Slack question
- **Browser history is useless**: `localhost:3000` history is a mix of unrelated projects
## Installation
Install globally (recommended) or as a project dev dependency. Do NOT use `npx` or `pnpm dlx` for one-off execution.
```bash
# Global (available everywhere)
npm install -g portless
# Or per-project dev dependency
npm install -D portless
```
When installed per-project, invoke via package.json scripts or `npx portless` (since the package is local, npx will not download anything).
## Quick Start
```bash
# Install globally (or add -D to a project)
npm install -g portless
# Run your app (auto-starts the HTTPS proxy on port 443)
portless run next dev
# -> https://<project>.localhost
# Or with an explicit name
portless myapp next dev
# -> https://myapp.localhost
```
The proxy auto-starts when you run an app. You can also start it explicitly with `portless proxy start`. Auto-start reuses the configuration (port, TLS, TLD) from the most recent proxy run, so a restart or reboot does not silently revert to defaults. Explicit env vars always take priority.
In non-interactive environments (no TTY, or `CI=1`), portless exits with a descriptive error instead of prompting. Task runners like turborepo should pre-start the proxy.
## Integration Patterns
### Zero-config (recommended)
Bare `portless` works out of the box. It runs the `"dev"` script from `package.json` through the proxy, inferring the app name from the package name, git root, or directory:
```bash
portless # -> runs "dev" script, https://<project>.localhost
pnpm dev # -> works without portless, plain "next dev"
```
Use an optional `portless.json` to override defaults (name, script, port):
```json
{ "name": "myapp" }
```
```bash
portless # -> runs "dev" script, https://myapp.localhost
```
### Monorepo
One `portless.json` at the repo root. Portless discovers packages from `pnpm-workspace.yaml`, or the `"workspaces"` field in `package.json` (npm, yarn, bun):
```json
{
"apps": {
"apps/web": { "name": "myapp" },
"apps/api": { "name": "api.myapp" }
}
}
```
```bash
portless # from repo root: start all packages with a "dev" script
cd apps/web && portless # start just one package
portless --script start # run "start" instead of "dev"
```
The `apps` map is optional and only provides name overrides. Unlisted packages auto-discover with inferred names.
Without an `apps` map, hostnames follow `<package>.<project>.localhost`. The project name comes from the most common npm scope (e.g. `@myorg/web` and `@myorg/api` produce `myorg`), falling back to the workspace root directory name. If a package's short name matches the project name, it uses the bare `<project>.localhost`.
### Turborepo
For turborepo projects, use portless as the `dev` script with the real command in a separate script:
```json
{
"scripts": { "dev": "portless", "dev:app": "next dev" },
"portless": { "name": "myapp", "script": "dev:app" }
}
```
`pnpm dev` runs turbo, which runs `portless` in each package. Portless detects the package manager and runs `pnpm run dev:app` through the proxy.
### package.json scripts
You can still use portless directly in scripts:
```json
{
"scripts": {
"dev": "portless run next dev"
}
}
```
The proxy auto-starts when you run an app. Or start it explicitly: `portless proxy start`.
### Multi-app setups with subdomains
```bash
portless myapp next dev # https://myapp.localhost
portless api.myapp pnpm start # https://api.myapp.localhost
portless docs.myapp next dev # https://docs.myapp.localhost
```
By default, only explicitly registered subdomains are routed (strict mode). Start the proxy with `--wildcard` to allow any subdomain of a registered route to fall back to that app (e.g. `tenant1.myapp.localhost` routes to the `myapp` app). Exact matches always take priority over wildcards.
### Git worktrees
`portless run` automatically detects git worktrees. In a linked worktree, the branch name is prepended as a subdomain prefix so each worktree gets a unique URL:
```bash
# Main worktree (no prefix)
portless run next dev # -> https://myapp.localhost
# Linked worktree on branch "fix-ui"
portless run next dev # -> https://fix-ui.myapp.localhost
```
No config changes needed. Put `portless run` in `package.json` once and it works in all worktrees.
### Bypassing portless
Set `PORTLESS=0` to run the command directly without the proxy:
```bash
PORTLESS=0 pnpm dev # Bypasses proxy, uses default port
```
## How It Works
1. `portless proxy start` starts an HTTPS reverse proxy on port 443 as a background daemon. Auto-elevates with sudo on macOS/Linux; falls back to port 1355 if sudo is unavailable. Use `--no-tls` for plain HTTP on port 80. Configurable with `-p` / `--port` or the `PORTLESS_PORT` env var. The proxy also auto-starts when you run an app.
2. `portless <name> <cmd>` assigns a random free port (4000-4999) via the `PORT` env var and registers the app with the proxy
3. The browser hits `https://<name>.localhost`; the proxy forwards to the app's assigned port
`.localhost` domains resolve to `127.0.0.1` natively in Chrome, Firefox, and Edge. Safari relies on the system DNS resolver, which may not handle `.localhost` subdomains on all configurations. Run `portless hosts sync` to add entries to `/etc/hosts` if needed.
Most frameworks (Next.js, Express, Nuxt, etc.) respect the `PORT` env var automatically. For frameworks that ignore `PORT` (Vite, VitePlus, Astro, React Router, Angular, Expo, React Native), portless auto-injects the correct `--port` flag and, when needed, a matching `--host` CLI flag.
### State directory
Portless stores its state (routes, PID file, port file) in `~/.portless`. Override with the `PORTLESS_STATE_DIR` environment variable.
### Environment variables
| Variable | Description |
| --------------------- | --------------------------------------------------------------------------- |
| `PORTLESS_PORT` | Override the default proxy port (default: 443 with HTTPS, 80 without) |
| `PORTLESS_APP_PORT` | Use a fixed port for the app (skip auto-assignment) |
| `PORTLESS_HTTPS` | HTTPS on by default; set to `0` to disable (same as `--no-tls`) |
| `PORTLESS_LAN` | Set to `1` to always enable LAN mode (auto-detects LAN IP) |
| `PORTLESS_LAN_IP` | Pin a specific LAN IP for LAN mode |
| `PORTLESS_TLD` | Use a custom TLD instead of localhost (e.g. test) |
| `PORTLESS_WILDCARD` | Set to `1` to allow unregistered subdomains to fall back to parent |
| `PORTLESS_SYNC_HOSTS` | Set to `0` to disable auto-sync of /etc/hosts (on by default) |
| `PORTLESS_TAILSCALE` | Set to `1` to share apps on your Tailscale network (same as `--tailscale`) |
| `PORTLESS_FUNNEL` | Set to `1` to share apps publicly via Tailscale Funnel (same as `--funnel`) |
| `PORTLESS_NGROK` | Set to `1` to share apps publicly via ngrok (same as `--ngrok`) |
Related in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.