Every dev server on your Mac, in the menu bar.
portbar shows what runs on which port, grouped by repository, worktree, and branch. It flags the server you forgot about and stops it in one click.
brew install 1fc0nfig/tap/portbarmacOS 14+ free MIT
lsof gives you a PID. portbar gives you the project.
bun run dev starts concurrently, which starts next dev, which starts its workers. Activity Monitor lists every one of them as node.
portbar folds the tree into one row: Next.js :3000, under the repository and branch it came from.
Memory and CPU add up across the whole tree. Package managers, shells, and runners stay out of your way under “Started by”.
Four dots. You already know what runs.
Each dot in the menu bar is a pinned project. Filled runs, a ring is stopped, orange or red wants a look. Click it, and every server sits under its repository, worktree, and branch.
Repository
portbar walks up from each process’s folder and reads
.gititself. Nogitprocess.~/dev/mailnail
Worktree and branch
Linked worktrees show under the repository they belong to, each on its own line with its branch.
feat/invoices
Pinned projects
Pin what you work on. It keeps its place in the panel and its dot in the menu bar, also when it is stopped.
up to 4 dots
Other
Anything outside a repository goes into one group at the bottom. One setting hides it.
always last
Prefer a plain icon? Switch the style in the demo. The icon turns into a warning triangle when something is flagged.
Run the script. Skip the terminal tab.
Start your scripts from the menu bar, read their logs in a real window, and stop the whole tree when you are done. Scripts portbar started stop when it quits, unless you turn that off.
package.json scripts
portbar reads them per project and runs them with your package manager, picked from the lockfile.
bun run dev
Your own commands
Add any command to a project, for example
docker compose up. It runs in your login shell, with your PATH.Settings › Projects
Starred scripts
Star a script and it becomes a button next to the pinned project. Up to two per project.
★ dev
Logs
Each run gets its own window with full ANSI color, a filter, and follow mode. Errors turn red even when the tool prints no color.
last 5,000 lines
Stop
One click stops the whole process tree, children first. Anything still alive after 3 seconds gets SIGKILL.
no orphan workers
Restart
Started it in a terminal? Restart runs the same command again inside portbar, now with logs.
same command
Find the one that spins the fan.
Every row carries a CPU sparkline of the last 60 scans, memory for the whole process tree, and uptime. Open a row for the full numbers. When a server misbehaves, the row says so in a word.
- Detached (orange). The outermost launcher has parent PID 1: the terminal that started it is gone.
- Forgotten (red). Detached, and running longer than 12 hours (the default, you can change it).
- High CPU (red). CPU above 80% for 3 scans in a row.
- Not responding (red). The HTTP probe on one of its ports timed out.
Forgotten
Detached, and running longer than you allow. You pick the limit, from one hour to three days, or never.
12 h by default
High CPU
Above 80% of a core for three scans in a row. One spike does not count.
> 80% × 3 scans
Not responding
The port is open, but the server does not answer HTTP. Only a timeout counts, a refused connection does not.
5 s timeout
Detached
The terminal or tool that started it is gone. Databases, Docker, and Ollama never get this flag.
parent pid 1
When anything is flagged, a bar at the bottom of the panel counts it. One button there stops every detached server, with whatever started it.
It knows what it is looking at.
portbar reads the command line and names the tool, with its mark. More than 45 frameworks, runtimes, and databases. Anything else shows its own executable name.
Playwright, Jupyter, the iOS Simulator, the Android Emulator, and adb get a system glyph instead of a logo. Brand marks from Simple Icons, drawn in one tint inside the app.
It reads the process table. That is all it reads.
A tool that can stop your processes should be boring to audit. portbar runs on your Mac and talks only to your Mac.
libproc, not lsof
Processes, ports, and branches come from system calls and a direct read of
.git. Nolsof, nops, nogit.proc_pidinfo
A quiet health check
The HTTP probe runs only while the panel is open, and asks each port at most once a minute. Your dev server logs stay clean.
GET /favicon.ico
No telemetry
No analytics, no crash reports, no update check. The only request the app makes goes to your own localhost.
localhost only
One shell, once
At launch, portbar starts your login shell once to read your environment, so your scripts get your PATH. After that it starts only the scripts you run.
$SHELL -lic
Native
Swift and SwiftUI, one universal build for Apple silicon and Intel. No Electron, no Dock icon.
macOS 14+
Open source
MIT licensed. Settings live in your user defaults, logs live in memory, and the source is one click away.
MIT
Do not take the page’s word for it. Read the source.
Questions
macOS says it cannot open portbar. Is something wrong?
No. portbar has an ad-hoc signature and is not notarized by Apple, so Gatekeeper stops the first launch of the DMG build. Right-click portbar in Applications, choose Open, and confirm. If macOS offers no Open button, go to System Settings, Privacy & Security, and click Open Anyway. You do this once. The Homebrew cask removes the quarantine flag, so a brew install opens normally.
What does it need?
macOS 14 Sonoma or later, on Apple silicon or Intel. It is one universal build. No Windows or Linux version.
Will it slow my Mac down?
It reads the process table through libproc, so a scan starts no other programs. It scans every 2 seconds while the panel is open (you can pick 1, 2, or 5) and every 5 seconds while it is closed. The HTTP check runs only while the panel is open, at most once a minute per port.
Which servers does it show?
Every process of yours that listens on a TCP port, plus known tools that run without one, such as Convex, Vitest, or a tsc watcher. It names more than 45 frameworks, runtimes, and databases. It skips system processes and app bundles. It sees Docker Desktop and OrbStack, not the containers inside them.
How does it find the repository and branch?
It walks up from the folder each process runs in and reads .git directly, without a git process. Linked worktrees show under the repository they belong to. A detached HEAD shows the short commit hash. Processes outside any repository go into a group called Other.
Does it stop or kill anything on its own?
No. Flags only tell you. A server stops when you click Stop: portbar sends SIGTERM to the whole process tree, children first, and SIGKILL after 3 seconds to anything still alive. Force Kill sends SIGKILL at once. Scripts that portbar started stop when it quits, and a setting turns that off.
Why not just use lsof or Activity Monitor?
If you need one PID for one port, lsof -i :3000 is fine. It does not tell you which project that PID belongs to, and Activity Monitor shows a dev server as a pile of node processes. portbar folds each tree into one named row, puts it under its repository and branch, and flags the one you forgot.
Does anything leave my Mac?
No. The app has no telemetry, no analytics, no crash reporting, and no update check. Its only network request is the health check to your own localhost.
How do I update it?
There is no auto-update. Run brew upgrade, or download the new DMG from GitHub Releases.
What does it cost?
Nothing. portbar is MIT licensed. If it finds a server you forgot, star the repository.
Stop asking what runs on :3000.
One line in the terminal, four dots in the menu bar. Free and open source.
brew install 1fc0nfig/tap/portbar