Skip to content

faladev/peakroute

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

96 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

npm version GitHub Windows macOS Linux

peakroute

Note

πŸ“Œ Fork Notice: This is a continuation fork of vercel-labs/portless. We maintain and extend the project with additional features and platform support.

Important

πŸͺŸ Windows Support Added! This fork includes full Windows support alongside macOS and Linux. No platform limitations!

Replace port numbers with stable, named .localhost URLs. For humans and agents.

- "dev": "next dev"              # http://localhost:3000
+ "dev": "peakroute myapp next dev"  # http://myapp.localhost:1355

Quick Start

# Install
npm install -g peakroute

# Start the proxy (once, no sudo needed)
peakroute proxy start

# Run your app (auto-starts the proxy if needed)
peakroute myapp next dev
# -> http://myapp.localhost:1355

The proxy auto-starts when you run an app. You can also start it explicitly with peakroute proxy start.

Why

Local dev with port numbers is fragile:

  • Port conflicts -- two projects default to the same port and you get EADDRINUSE
  • Memorizing ports -- was the API on 3001 or 8080?
  • Refreshing shows the wrong app -- stop one server, start another on the same port, and your open tab now shows something completely different
  • Monorepo multiplier -- every problem above scales with each service in the repo
  • Agents test the wrong port -- AI coding agents guess or hardcode the wrong port, especially in monorepos
  • Cookie and storage clashes -- cookies set on localhost bleed across apps on different ports; localStorage is lost when ports shift
  • Hardcoded ports in config -- CORS allowlists, OAuth redirect URIs, and .env files all break when ports change
  • Sharing URLs with teammates -- "what port is that on?" becomes a Slack question
  • Browser history is useless -- your history for localhost:3000 is a jumble of unrelated projects

Peakroute fixes all of this by giving each dev server a stable, named .localhost URL that both humans and agents can rely on.

Usage

# Basic
peakroute myapp next dev
# -> http://myapp.localhost:1355

# Subdomains
peakroute api.myapp npm start
# -> http://api.myapp.localhost:1355

peakroute docs.myapp next dev
# -> http://docs.myapp.localhost:1355

In package.json

{
  "scripts": {
    "dev": "peakroute myapp next dev"
  }
}

The proxy auto-starts when you run an app. Or start it explicitly: peakroute proxy start.

How It Works

flowchart TD
    Browser["Browser<br/>myapp.localhost:1355"]
    Proxy["peakroute proxy<br/>(port 1355)"]
    App1[":4123<br/>myapp"]
    App2[":4567<br/>api"]

    Browser -->|port 1355| Proxy
    Proxy --> App1
    Proxy --> App2
Loading
  1. Start the proxy -- auto-starts when you run an app, or start explicitly with peakroute proxy start
  2. Run apps -- peakroute <name> <command> assigns a free port and registers with the proxy
  3. Access via URL -- http://<name>.localhost:1355 routes through the proxy to your app

Apps are assigned a random port (4000-4999) via the PORT and HOST environment variables. Most frameworks (Next.js, Express, Nuxt, etc.) respect these automatically. For frameworks that ignore PORT (Vite, Astro, React Router, Angular), peakroute auto-injects the correct --port and --host flags.

HTTP/2 + HTTPS

Enable HTTP/2 for faster dev server page loads. Browsers limit HTTP/1.1 to 6 connections per host, which bottlenecks dev servers that serve many unbundled files (Vite, Nuxt, etc.). HTTP/2 multiplexes all requests over a single connection.

# Start with HTTPS/2 -- generates certs and trusts them automatically
peakroute proxy start --https

# First run prompts for sudo once to add the CA to your system trust store.
# After that, no prompts. No browser warnings.

# Make it permanent (add to .bashrc / .zshrc)
export PEAKROUTE_HTTPS=1
peakroute proxy start    # HTTPS by default now

# Use your own certs (e.g., from mkcert)
peakroute proxy start --cert ./cert.pem --key ./key.pem

# If you skipped sudo on first run, trust the CA later
sudo peakroute trust

Commands

peakroute <name> <cmd> [args...]  # Run app at http://<name>.localhost:1355
peakroute list                    # Show active routes
peakroute trust                   # Add local CA to system trust store

# Disable peakroute (run command directly)
PEAKROUTE=0 bun dev              # Bypasses proxy, uses default port
# Also accepts PEAKROUTE=skip

# Proxy control
peakroute proxy start             # Start the proxy (port 1355, daemon)
peakroute proxy start --https     # Start with HTTP/2 + TLS
peakroute proxy start -p 80       # Start on port 80 (requires sudo)
peakroute proxy start --foreground  # Start in foreground (for debugging)
peakroute proxy stop              # Stop the proxy

# Options
-p, --port <number>              # Port for the proxy (default: 1355)
                                 # Ports < 1024 require sudo
--https                          # Enable HTTP/2 + TLS with auto-generated certs
--cert <path>                    # Use a custom TLS certificate (implies --https)
--key <path>                     # Use a custom TLS private key (implies --https)
--no-tls                         # Disable HTTPS (overrides PEAKROUTE_HTTPS)
--foreground                     # Run proxy in foreground instead of daemon
--force                          # Override a route registered by another process
--inject                         # Force injection of --port and --host flags

# Environment variables
PEAKROUTE_PORT=<number>           # Override the default proxy port
PEAKROUTE_HTTPS=1                 # Always enable HTTPS
PEAKROUTE_STATE_DIR=<path>        # Override the state directory
PEAKROUTE_NO_UPDATE_CHECK=1       # Disable update availability notifications

# Environment variables set by peakroute
PEAKROUTE_URL                     # The public .localhost URL (e.g., http://myapp.localhost:1355)

# Info
peakroute --help                  # Show help
peakroute --version               # Show version

Update Notifications

Peakroute automatically checks for updates once per day and shows a notification when a new version is available:

β†’ Update available: 0.5.9 (current: 0.5.8)
  Run: npm install -g peakroute

To disable these notifications, set the environment variable:

export PEAKROUTE_NO_UPDATE_CHECK=1

State Directory

Peakroute stores its state (routes, PID file, port file) in a directory that depends on the proxy port:

  • Port < 1024 (sudo required): /tmp/peakroute -- shared between root and user processes
  • Port >= 1024 (no sudo): ~/.peakroute -- user-scoped, no root involvement

Override with the PEAKROUTE_STATE_DIR environment variable if needed.

Update Notifications

Peakroute automatically checks for updates once per day and shows a friendly notification when a new version is available:

β†’ Update available: 0.5.9 (current: 0.5.8)
  Run: npm install -g peakroute

The check is cached for 24 hours to avoid unnecessary network requests. To disable update notifications, set the environment variable:

export PEAKROUTE_NO_UPDATE_CHECK=1

Development

This repo is a Bun workspace monorepo using Turborepo. The publishable package lives in packages/peakroute/.

bun install          # Install all dependencies
bun run build        # Build all packages
bun run test         # Run tests
bun run test:coverage # Run tests with coverage
bun run test:watch   # Run tests in watch mode
bun run lint         # Lint all packages
bun run typecheck    # Type-check all packages
bun run format       # Format all files with Prettier

Proxying Between Peakroute Apps

If your frontend dev server (e.g. Vite, webpack) proxies API requests to another peakroute app, make sure the proxy rewrites the Host header. Without this, the proxy sends the original Host header, causing peakroute to route the request back to the frontend in an infinite loop.

Vite (vite.config.ts):

server: {
  proxy: {
    "/api": {
      target: "http://api.myapp.localhost:1355",
      changeOrigin: true,  // Required: rewrites Host header to match target
      ws: true,
    },
  },
}

webpack-dev-server (webpack.config.js):

devServer: {
  proxy: [{
    context: ["/api"],
    target: "http://api.myapp.localhost:1355",
    changeOrigin: true,  // Required: rewrites Host header to match target
  }],
}

Peakroute detects this misconfiguration and responds with 508 Loop Detected along with a message pointing to this fix.

Requirements

  • Node.js 20+
  • macOS, Linux, or Windows

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors