Portless automatically detects git worktrees and uses the branch name as a subdomain prefix. This gives each worktree its own URL without any configuration changes or name collisions.
cd ~/projects/myapp # main branchportless run next dev# -> http://myapp.localhost:1355
The branch name is converted to a subdomain prefix:
10
auto.ts
function branchToPrefix(branch: string): string | null { // Skip default branches if (!branch || branch === "HEAD" || ["main", "master"].includes(branch)) { return null; } // Use only the last segment after the final / // e.g., "feature/auth" -> "auth" const lastSegment = branch.split("/").pop()!; // Sanitize for use as a DNS label const prefix = sanitizeForHostname(lastSegment); return prefix || null;}
The main worktree (on main or master) gets no prefix:
git worktree list# /home/user/myapp main [main]# /home/user/fix-ui fix-ui [fix-ui]cd /home/user/myappportless run next dev# -> http://myapp.localhost:1355 (no prefix)
git checkout -b feature/authportless run next dev# -> http://auth.myapp.localhost:1355git checkout -b bugfix/api/rate-limitportless run next dev# -> http://rate-limit.myapp.localhost:1355
Use the --no-worktree flag with portless get to skip worktree detection:
# In a worktree on branch fix-uiportless get backend# -> http://fix-ui.backend.localhost:1355portless get backend --no-worktree# -> http://backend.localhost:1355
This is useful when you need a consistent URL regardless of the current worktree.
There is currently no flag to disable worktree detection for portless run or portless <name>. If you need this, use --name to force a specific name:
portless --name myapp next dev# -> http://myapp.localhost:1355 (no worktree prefix)
Worktree URLs benefit from wildcard subdomain routing. If you register myapp.localhost, then:
myapp.localhost routes to your app
fix-ui.myapp.localhost routes to your app
auth.myapp.localhost routes to your app
anything.myapp.localhost routes to your app
This means you can run multiple worktrees without explicitly registering each one:
# Main worktree registers the base namecd ~/myappportless run next dev# Registers: myapp.localhost -> 4123# Worktree automatically routes via wildcardcd ~/worktrees/myapp-fix-uiportless run next dev# Registers: fix-ui.myapp.localhost -> 4567# Routes via wildcard: *.myapp.localhost -> 4123 (main app)
Wildcard routing matches the longest registered suffix. If you explicitly register fix-ui.myapp.localhost, that route takes precedence over the wildcard match for myapp.localhost.