Skip to content

Languages and Runtimes

PortBay uses a detect-first model: it scans your machine for runtimes that are already installed — via Homebrew, nvm, mise, asdf, pyenv, rbenv, ServBay, or the system PATH — and surfaces them without installing or bundling anything itself. Each language shows all detected versions, lets you pick a default for new projects, and (for runtimes that have daemon or package-manager config) exposes editable settings panels. The Languages screen provides a single place to see what is installed, where it came from, and how PortBay will use it.

PortBay languages

Quickstart

  1. Open the Languages tab in the sidebar.
  2. PortBay scans your machine and lists detected versions under each language. A version count appears in the group header; a dot indicates nothing was found.
  3. Click any version row to open its config panel on the right.
  4. To make a version the default for new projects, click Set as default in the header strip. The row gains a default badge.

If a language has no detected versions, the sidebar shows the install command. For Homebrew-managed runtimes you can click Install via Homebrew to run the install directly from PortBay; the button streams Homebrew's output inline. You can also click the install-command text to copy it.

How-to

Set a default version

Select a version in the left rail, then click Set as default in the right-pane header. The button label changes to "Default for new projects" and the default badge appears on the version row.

To clear the default, click the same button again while that version is already marked as default.

Add a runtime by path

If the detector missed a binary — for example a version managed by a tool PortBay doesn't enumerate, or a custom build — click Add by path… under the relevant language group. A file picker opens; select the primary binary. PortBay probes its version string and registers it as a Manual install. The binary is never copied or moved.

To remove a manually-added entry, select it and click Remove in the header strip. The binary on disk is not touched.

Edit a version's configuration

Select a version. If it has editable settings, one or more tabs in the right pane contain form fields rather than read-only values. Make your changes — a small dot on the field label marks unsaved edits — then click Save changes. Changes are applied immediately; runtimes that have a daemon (PHP-FPM) restart that daemon automatically.

Read-only tabs (info panes, extension lists) have no Save button.

Rescan

Click the refresh icon in the Languages rail header to re-run detection without restarting the app. This is useful after installing a new runtime version.

Per-language detection sources and config

PHP

Detection: Homebrew formulae (php, php@8.x), ServBay (/Applications/ServBay/), FlyEnv, and the system PATH.

Install hint: brew install php@8.3

Config tabs:

TabEditableWhat it covers
FPMYesProcess manager (dynamic/static/ondemand), worker counts, listen mode (socket or TCP), slow-log, raw pool directives. Saving restarts the FPM process for this version.
PHPYesphp.ini overrides applied per-pool via php_admin_value — the system php.ini is never edited. Fields: memory_limit, upload_max_filesize, post_max_size, max_execution_time, date.timezone. Blank value clears the override.
ExtensionsNoAll loaded extensions for this version (php -m).

Node.js

Detection: Homebrew (node, node@<ver>), nvm (~/.nvm/versions/node/<ver>/, $NVM_DIR honoured), asdf (~/.asdf/installs/nodejs/<ver>/), mise (~/.local/share/mise/installs/node/<ver>/), system PATH.

Install hint: brew install node

Config tabs:

TabEditableWhat it covers
RegistryYesnpm/pnpm registry URL, written to ~/.npmrc. Shared across all Node versions. Blank restores the default (registry.npmjs.org).
CacheYesnpm cache directory, written to ~/.npmrc (cache key). Blank uses npm's default (~/.npm).

Node has no daemon; changes take effect the next time a process reads ~/.npmrc.

Bun

Detection: Homebrew (bun, bun@<ver>), the official installer location (~/.bun/bin/bun, $BUN_INSTALL honoured), asdf, mise, system PATH.

Install hint: brew install oven-sh/bun/bun

Config tabs: Read-only Info tab (binary path, install source). No editable config in this release.

Python

Detection: Homebrew (python, python@<ver>), pyenv (~/.pyenv/versions/<ver>/, pyenv root and $PYENV_ROOT honoured), asdf, mise, system PATH (python3, python).

Install hint: brew install python

Config tabs:

TabEditableWhat it covers
Package indexYespip index URL, written to pip.conf [global] section (~/Library/Application Support/pip/pip.conf on macOS). Shared across all Python versions. Blank restores PyPI.

Python has no daemon; changes apply on the next pip invocation.

Go

Detection: Homebrew (go), asdf (~/.asdf/installs/golang/<ver>/go/bin/go), mise, system PATH.

Install hint: brew install go

Config tabs:

TabEditableWhat it covers
EnvironmentYesGOPROXY (module proxy URL, comma list, direct, or off) and GOPATH (workspace root), written to the Go env file ($GOENV or ~/Library/Application Support/go/env). Shared across all Go versions.

Go has no daemon; changes apply to the next go command.

Ruby

Detection: Homebrew (ruby), rbenv (~/.rbenv/versions/, rbenv root and $RBENV_ROOT honoured), asdf, mise, system PATH.

Install hint: brew install ruby

Config tabs:

TabEditableWhat it covers
RubyGemsYesDefault gem flags (gem key in ~/.gemrc). Shared across all Ruby versions. Blank removes the override. The :sources: list in .gemrc is left untouched.

Ruby has no daemon; changes apply on the next gem command.

Flutter

Detection: Homebrew (brew install --cask flutter), asdf, mise, system PATH.

Install hint: brew install --cask flutter

Config tabs: Read-only Info tab (binary path, install source). No editable config.

Reference

Install sources

These are the values the source pill on each version row can show.

ValueLabelWhere the install came from
homebrewHomebrewHomebrew formula under the user's brew prefix
serv_bayServBayServBay-managed package
fly_envFlyEnvFlyEnv-managed package
asdfasdfasdf-vm — ~/.asdf/installs/<lang>/<ver>/
misemisemise — ~/.local/share/mise/installs/<lang>/<ver>/
nvmnvmnvm — ~/.nvm/versions/node/<ver>/ (Node only)
pyenvpyenvpyenv — ~/.pyenv/versions/<ver>/ (Python only)
systemSystemFound on $PATH without a recognised version manager
manualManualAdded by the user via "Add by path"

Data shapes

LanguageView

One entry per supported language returned by list_runtimes.

FieldTypeDescription
idstringStable identifier: "php", "node", "bun", "python", "go", "ruby", "flutter"
displayNamestringHuman label, e.g. "Node.js"
versionsVersionView[]Detected versions, newest first
installHintstringCommand shown when versions is empty
defaultVersionstring | nullVersion string marked as default, or null

VersionView

One detected install coupled with its config panel.

FieldTypeDescription
installRuntimeInstallDetection result
tabsConfigTab[]Config tabs to render in the right pane

RuntimeInstall

FieldTypeDescription
versionstringSemantic version label, e.g. "8.3", "22.11.0"
binarystringAbsolute path to the primary binary
sourceInstallSourceWhere the install came from
configDirstring | nullPortBay-managed config directory (PHP only; null for most runtimes)

ConfigTab

FieldTypeDescription
idstringStable tab identifier used as the key when posting edits
labelstringDisplay label shown in the tab bar
rowsKvRow[]Fields in this tab
editablebooleantrue if the tab has at least one editable row and shows a Save button

KvRow

FieldTypeDescription
keystringKey edits are posted under (ignored for readonly rows)
labelstringField label
valuestringCurrent persisted value
hintstring | undefinedOptional hint shown beneath the field
isPathbooleanWhen true, the value renders as a monospace path with a Reveal in Finder button
fieldFieldKindHow the row renders and whether it accepts edits

FieldKind

Internally tagged on kind.

kindAdditional fieldsBehaviour
readonlyDisplay-only. Value shown with a copy button; isPath rows also get a Finder reveal button. Never sent on save.
textSingle-line free-text input.
numbermin?: number, max?: numberNumeric input. Optional bounds clamp the stepper.
selectoptions: string[]Dropdown. Value must be one of options.
boolCheckbox. Value is the string "true" or "false".
textareaMulti-line free-text input.

IPC commands

CommandArgumentsReturnsDescription
list_runtimesLanguageView[]Scan all languages and return the full view. Per-version config tabs are pre-computed so the panel renders without a second round-trip.
install_runtimelang: string, onEvent: ChannelDelegate brew install for a missing runtime. Streams { kind: "log", line } and { kind: "done", success } events.
set_default_runtimelang: string, version: string | nullLanguageView[]Set or clear the default version for a language. Returns the updated list.
add_runtime_by_pathlang: string, path: stringLanguageView[]Register an existing binary as a Manual install. Returns the updated list.
update_runtime_configlang: string, version: string, tabId: string, patches: Record<string, string>LanguageView[]Persist edits from one tab and return the updated list with server-side values.
remove_runtime_pathlang: string, version: stringLanguageView[]Remove a Manual install entry. The binary is not deleted. Returns the updated list.

PortBay is pre-MVP software. Use the docs as an operating guide, not a stability guarantee.