Skip to content

How to Run Multiple Dev Servers Without a Pile of Terminal Tabs

A normal day on a few projects means a Laravel API, a Vite front end, maybe a GeoServer or a queue worker — each one a long-running command in its own folder. Getting them all running is not hard. Doing it after every login, and stopping them cleanly, is where the time goes.

Why running several servers gets tedious

Each server is a foreground process that owns a terminal until you stop it. That leaves you with three recurring costs: opening one tab per server and cd-ing into the right folder, remembering which command each project uses, and finding out later that a server you thought you had stopped is still holding its port.

Five ways to do it

A terminal tab per server

Good at: Zero setup, and you see exactly what the server prints.

Costs: Every login means opening tabs and cd-ing into each project again. Nothing remembers what you had running.

tmux or a terminal multiplexer

Good at: Sessions survive closing the terminal window, and the layout is scriptable.

Costs: It is another tool with its own key bindings to learn, and you still write and maintain the startup script.

A process runner (Procfile, npm-run-all, concurrently)

Good at: One command starts a project's own processes together.

Costs: It works inside one project. Servers that live in different repositories and stacks still need starting separately.

docker compose

Good at: Reproducible, isolated services with one command.

Costs: It assumes everything is containerised. A php artisan serve or npm run dev on the host does not fit.

A desktop launcher

Good at: Projects across any stack in one window, with per-run logs and Run All / Stop All.

Costs: It is one more app to install, and it suits host-run servers rather than containers.

The two problems a launcher has to get right

Stopping cleanly. A start command usually runs through a shell, and the shell can fork the real server as a child. Signal only the shell and the child keeps running, still bound to its port. On macOS and Linux, Automus starts every run in its own session and, on Stop, sends SIGTERM to the entire process group — then SIGKILL after a three-second grace period if anything ignored it.

Finding your tools. An app opened from the Dock or a launcher gets a bare default PATH. Homebrew, nvm and XAMPP usually add themselves in ~/.zshrc, which only a shell reads. Automus runs each command through your own login shell, so the same npm and php that work in your terminal work in the app.

What Automus runs for a project
$ cd ~/dev/laravel-api
$ $SHELL -ilc "php artisan serve" # in its own session
$ kill -TERM -<group> # Stop; SIGKILL after 3 s

Where Automus fits

Automus is a desktop launcher for servers that run on your machine. You register a project once — its root folder and start command — and then use ▶ to run it. That default command lives in one fixed slot, so pressing it again restarts the same run instead of spawning a duplicate. The + button starts any other command in that folder as an independent, concurrent run. Every run gets its own tab with live, color-coded output, and Run All and Stop All act across every project.

It is not a container orchestrator and not a terminal multiplexer, and it does not try to be. If your whole stack is already in docker compose, keep using that.

Frequently asked questions

How do I run several dev servers at the same time?

Each server needs its own long-running process, so the usual options are one terminal tab per server, a terminal multiplexer such as tmux, a script that starts them together (a Procfile runner, npm-run-all or concurrently), docker compose, or a desktop launcher. A launcher such as Automus keeps each project's folder and start command saved, so you press one button instead of re-typing them after every login.

Why do dev servers keep running after I close the terminal or the app?

A start command usually goes through a shell, and the shell may fork the real server as a child. Stopping only the shell leaves the child running, still holding its port. The reliable fix is to signal the whole process group. Automus starts each run in its own session and, on Stop, sends SIGTERM to the entire group, then SIGKILL after a three-second grace period if anything is still alive.

Why can't my desktop app find npm, php or node when a terminal can?

An app launched from the Dock, Start menu or a launcher inherits a bare default PATH. Tools added by Homebrew, nvm or XAMPP are usually put on PATH in ~/.zshrc or ~/.zprofile, which only a shell reads. On macOS and Linux, Automus runs every command through your own login shell (-ilc), so those profile files are sourced and the same tools resolve as in your terminal.

What happens if I press Run again on a server that is already running?

In Automus, a project's default command lives in one fixed slot. Pressing Run again reuses or restarts that same run instead of starting a second copy, which is what prevents two processes from fighting over one port. One-off commands started with + are separate runs and can run concurrently.

Is Automus a replacement for docker compose or tmux?

No. docker compose is for running containerised services; tmux is a terminal multiplexer. Automus is for the case where your servers are ordinary commands run from folders on your own machine and you want a window that starts, stops and shows the logs of all of them — without containers, and without a terminal session to keep alive.

Does Automus send any of my data anywhere?

No. It has no account, no sign-in and no telemetry, and makes no network requests of its own. Your projects are stored in a JSON file in the operating system's app-data folder. The only network traffic is whatever the commands you start generate.