Use cases

Why port 3000 stays free

OAuth providers, Stripe webhooks, Mapbox API keys, and CORS allowlists are all registered to localhost:3000. That works when you have one copy of the app. It breaks the moment you run two.

The problem

Git worktrees let you work on multiple branches at the same time, each in its own directory. But each copy of the app needs its own port — branch A on 3000, branch B on 3010, branch C on 3020. The moment branch B starts on port 3010:

You’re forced to choose: run on the “right” port and stop all other branches, or reconfigure every third-party dashboard for every branch. Neither scales.

The design decision

Treeline deliberately never allocates port 3000 — or any common framework default (4000, 5000, 8000, 8080). Worktree servers bind to ports in a managed range that the developer never needs to type. Port 3000 stays empty so the proxy can claim it.

gtl proxy 3000 sits on the port that third-party services expect and routes traffic to whichever worktree you’re working on. The external world always sees localhost:3000. You rotate what’s behind it.

$ gtl proxy 3000

Proxying :3000:4010 (feature-auth)

# OAuth callback → :4010 ✓

# Stripe webhook → :4010 ✓

# Mapbox origin → :4010 ✓

# CORS passes → :4010 ✓

Two layers, one config

The proxy handles what’s external. Branch-named URLs handle what’s local. Both run simultaneously:

Audience URL How
Your browser myapp-feature.prt.dev gtl serve
OAuth / Stripe / Maps / CORS localhost:3000 gtl proxy
Public internet (webhooks, CI) myapp-feature.example.dev gtl tunnel
A colleague or client Disposable token-gated URL gtl share

What the developer sees

# Create a worktree — treeline allocates port 4010

$ gtl new feature/oauth-refactor

Allocated port 4010, cloned database, wrote .env

# Start the server — runs on 4010, not 3000

$ gtl start

==> https://myapp-feature-oauth-refactor.prt.dev

# Route port 3000 to this worktree

$ gtl proxy 3000

Proxying :3000:4010

No port numbers in the browser. No OAuth reconfiguration. No Stripe dashboard changes. The developer works on any branch, and the external world sees the same origin it always has.

Read next

All use cases