LocalRun

Add a project

Click the LocalRun icon in the menu bar, then the + button in the header (or Add New Project if the list is empty). The form opens in two modes.

Folder mode: LocalRun runs the server

Choose a folder and LocalRun inspects it before you type anything:

  • If the folder has a .localrun.json, every field comes from there.
  • Otherwise it reads package.json and proposes <pm> run dev (falling back to start), where <pm> is inferred from the lockfile: pnpm-lock.yaml, bun.lock, yarn.lock, or package-lock.json.
  • The port is picked up from a --port, -p, or PORT= in that script. If the script has none but something is already listening for that directory, the live port is used.
  • The name defaults to the folder name, lowercased and hyphenated.
FieldWhat it does
NameBecomes <name>.test. Lowercase letters, digits and dashes, must start with a letter or digit, 63 characters max.
PortWhere your server listens. Leave it blank and LocalRun detects it from the startup output.
Run commandWhat LocalRun executes to start the server. Leave blank if you start it yourself.
Build commandWhat the Rebuild button runs before restarting.
Open in Terminal runsThe command a new terminal window types when you hit Open in Terminal: claude, nvim ., whatever.
Keep runningManual, with LocalRun, or Always. See Keep running.
SchemeHTTPS with a locally trusted certificate, or plain HTTP.

Submit, and the site is live at https://<name>.test. If you set a run command, Start is enabled on the row.

Blank port is usually the right answer

With no port set, LocalRun watches the process output for lines like listening on 3000 or http://localhost:5173, then reloads Caddy once it knows. That survives a framework picking a different port because yours was taken; a hardcoded port does not.

Port mode: LocalRun only proxies

Give it a name and a port, no folder. Use this for a server you start yourself in a terminal, a container publishing a port, or anything else already listening. LocalRun routes <name>.test to 127.0.0.1:<port> and nothing else; it will not try to start or stop it.

Adopting something already running

The panel has a Running on this Mac section listing local servers LocalRun did not start, with the folder and git branch it traced them back to. Adopt w/LocalRun gives one a .test name without restarting it.

What you can then do with that row depends on what the process is: LocalRun classifies it and only offers what will actually work. Killing a docker-proxy does not stop the container, and signalling a launchd-supervised process just makes launchd restart it. Service kinds has the full table.

Pin it in .localrun.json

A .localrun.json in the project root makes the setup reproducible and checks into git, so a teammate adding the folder gets the same name, port and command:

jsonc
{
  "name": "my-scraper",
  "runCommand": "npm run dev",
  "buildCommand": "npm run build",
  "port": 3000,
  "tls": "auto",
  "health": "/health",
  "keepRunning": "localrun",
  "envFile": ".env.local",
  "env": { "NODE_ENV": "development" },
  "terminalCommand": "claude"
}
FieldWhatRequired
nameThe hostname. Becomes <name>.test. Must match ^[a-z0-9][a-z0-9-]{0,62}$no, defaults to the folder name
runCommandShell command that starts the serveronly if you want LocalRun to start it
buildCommandShell command the Rebuild button runs before restartingno
portUpstream port, 1-65535. Omit to auto-detectno
tlsauto for HTTPS or off for plain HTTPno; omitted means your default scheme setting, which ships as HTTPS
healthPath to poll for the health dot, e.g. /health. Checked every 10sno
keepRunningmanual, localrun, or always; see Keep runningno
envEnvironment variables as an objectno
envFilePath to a dotenv file, relative to the projectno
terminalCommandWhat Open in Terminal runs. {{dir}}, {{name}}, {{port}} and {{url}} are substitutedno

The file is read when you add the folder and when you re-detect it; editing it does not retroactively rewrite a project you already added. Change those fields in the tray, or remove the project and add it again.

Rebuild needs buildCommand

The Rebuild button runs buildCommand and then restarts. It only appears on rows that have one set. If you cannot find it, that is why.

Working with a row

Click a row to expand it. Three tabs:

  • Info: the URL, the port and where it came from, the process, and the actions the daemon says this kind of service supports.
  • Logs: a live tail of stdout and stderr, with copy and clear. Log files are keyed by project id, so renaming a project keeps its history.
  • Env: a plain-text editor for the project's environment. Saving restarts the process if it is running. Variables only apply to processes LocalRun starts.

Next

How it works explains what the daemon does with all this. If your project should still be up after a reboot, go to Keep running.