Portside

See every dev server on your Mac. Start it, stop it, open it — from the menu bar.

Free and open source. Native SwiftUI, one 1.2 MB binary. It never touches the network.

brew install --cask tdrach/tap/portside

Or download it directly. Needs macOS 14 or newer. Apple Silicon and Intel.

Portside3 running
  • api:3000npm run dev223 MB
  • frontend:5173npm run dev1.2 GB
  • worker:8080npm run start14 GB
  • docs:4000npm run docs
+ Add server

Stop hunting through terminal tabs

Your servers live in one list. Each row can start, stop, and open its server. Portside finds running servers by itself and names them after their project folder.

“What is running on port 3000?”

Answered at a glance. The menu bar icon shows a live count of running servers. Open the list and every port has a name.

Catch the memory leak

Long-running dev servers leak memory. Each row shows what its server really uses — the whole process tree, not one process. Gray is fine. Amber means past 2 GB. Red means past 6 GB. Restart it before it eats 14 GB.

One click after a reboot

Group servers that belong together — api, frontend, worker — and start or stop them as one unit. Ordered start waits until each server is really listening before the next one launches.

How it works

Every 4 seconds, Portside asks macOS what is listening on which port. It uses lsof, the same tool you would use by hand. Nothing is scanned over the network.

It reads each process’s working folder. That is how a row gets your project’s name. It also reads your package.json to learn the restart command — npm, pnpm, yarn, and bun all work. Once Portside has seen a server once, restarting it is one click forever.

Servers Portside starts run in their own process group. A process group is a family of processes that belong together. Stopping the row stops the whole family — the npm → node → worker tree, not just the parent. Each of these servers also gets its own log file (row menu → View log).

The memory numbers come from the same system calls Activity Monitor uses, summed over the tree. And your version managers just work: Portside captures your login shell’s environment at startup, so nvm, asdf, mise, and volta paths all resolve.

Questions

Does it phone home?

No. Portside never opens a network connection. Not for updates. Not for analytics. Not once. Don’t take our word for it — run Little Snitch and watch: nothing ever shows up. Or run lsof -i -p $(pgrep Portside) and see it come back empty. The only network use is when you click something that opens your browser.

Is it safe to run?

The code is public on GitHub under the MIT license. The app is signed with an Apple Developer ID and notarized — that means Apple scanned it and vouched for it. It validates even offline. It writes files only inside its own folder in Application Support. It reads package.json in your projects, but it never writes there.

Can it kill the wrong thing?

No. Portside never signals a process it cannot tie to a row. Servers it started are stopped as a whole tree: a polite signal first, then force after 3 seconds. Servers it did not start get more patience — 10 seconds, and it re-checks the process is still the same one before forcing. If another app sits on a saved port, Portside leaves it alone. Removed rows stay removed, too: auto-restarting tools like nodemon cannot resurrect a server you deleted.

Why does macOS ask about my Documents folder?

Portside reads package.json to build restart commands. It only reads. Say no, and everything still works — it just cannot guess commands for you.

Why isn’t it in the Mac App Store?

App Store rules put every app in a sandbox. A sandboxed app cannot list other processes or send them signals. That is Portside’s whole job. So it ships directly, signed and notarized by Apple. That is the only honest way to ship this tool.

How do updates work?

Run brew upgrade --cask portside. Or use “Check for updates” in the app’s ⋯ menu. The app never checks on its own.

What does it cost?

Nothing. Portside is free, MIT-licensed, and the source is on GitHub.