Skip to main content

Quickstart

Get Portless up and running in under 2 minutes.

Installation

1

Install Portless globally

Install via npm:
npm install -g portless
Portless requires Node.js 20+ and works on macOS and Linux.
2

Run your first app

Navigate to any project and run your dev server through Portless:
portless run next dev
Or specify a name explicitly:
portless myapp next dev
The proxy will auto-start if needed, and your app will be available at:
http://myapp.localhost:1355
The name is automatically inferred from your package.json, git repo, or directory name when you use portless run.
3

Access your app

Open your browser and visit:
http://myapp.localhost:1355
That’s it! Your app is now running with a stable, human-readable URL.

First Commands

Run with Auto-Inferred Name

Portless automatically infers your project name from package.json, git repo, or directory:
portless run next dev
# -> http://<project>.localhost:1355

Run with Explicit Name

Specify the name directly:
portless myapp next dev
# -> http://myapp.localhost:1355

Use Subdomains

Organize related services under the same domain:
portless api.myapp pnpm start
# -> http://api.myapp.localhost:1355

portless docs.myapp npm run dev
# -> http://docs.myapp.localhost:1355

Add to package.json

Make Portless the default for your project:
package.json
{
  "scripts": {
    "dev": "portless run next dev"
  }
}
Now anyone on your team can just run npm run dev and get a stable URL.
The proxy auto-starts when you run an app. You can also start it explicitly with portless proxy start.

Working Example

Let’s say you’re building a full-stack app with a Next.js frontend and an Express API.
1

Start the API

cd api
portless api.myapp node server.js
Your API is now running at http://api.myapp.localhost:1355.
2

Start the frontend

cd frontend
portless myapp next dev
Your frontend is now running at http://myapp.localhost:1355.
3

Configure the frontend to call the API

Update your frontend to call the API by its stable URL:
app/api/route.ts
export async function GET() {
  const response = await fetch('http://api.myapp.localhost:1355/data');
  const data = await response.json();
  return Response.json(data);
}
No more hardcoded port numbers. The URL stays the same even if the underlying port changes.

Git Worktree Support

If you use git worktrees, Portless automatically detects them and prepends the branch name as a subdomain:
# Main worktree (main/master branch)
portless run next dev
# -> http://myapp.localhost:1355

# Linked worktree on branch "fix-ui"
portless run next dev
# -> http://fix-ui.myapp.localhost:1355

# Linked worktree on branch "feature/auth"
portless run next dev
# -> http://auth.myapp.localhost:1355
This means you can put portless run in your package.json once and it just works everywhere - the main checkout uses the plain name, and each worktree gets a unique subdomain. No --force needed, no name collisions.
You can disable Portless temporarily by setting PORTLESS=0 or PORTLESS=skip when running commands.

Managing the Proxy

The proxy starts automatically when you run an app, but you can also control it manually:
portless proxy start

Environment Variables Injected

When you run an app through Portless, these environment variables are automatically injected:
VariableDescriptionExample
PORTThe port your app should listen on4123
HOSTThe host your app should bind to127.0.0.1
PORTLESS_URLThe public URL to access your apphttp://myapp.localhost:1355
Most frameworks automatically respect PORT and HOST. For frameworks that don’t, Portless auto-injects the correct flags.

Static Aliases (Advanced)

If you have a service running outside of Portless (like a Docker container), you can register it manually:
portless alias db 5432
# -> http://db.localhost:1355 routes to localhost:5432
To remove an alias:
portless alias --remove db

Next Steps

Why Portless?

Learn about the problems Portless solves and real-world use cases

Environment Variables

Configure Portless with environment variables and advanced options
If you’re using Safari and .localhost URLs don’t resolve, run sudo portless hosts sync. Safari relies on the system DNS resolver which may not handle .localhost subdomains on all configurations.

Build docs developers (and LLMs) love