Why stackctl
A monorepo with a few services takes a ritual to start. A terminal per service. A docker compose up you have to remember. An order that matters, because the frontend fails until the API answers. .env files loaded a different way by each service. Then a second version of all of it for the e2e suite, a third for CI, and a fourth explained to a coding agent in a prompt.
stackctl replaces the ritual with one config file and one command.
One description, used everywhere
stackctl.config.ts says what the services are, what each one needs, and how to tell it is ready. Everything else reads that file:
| You want to… | Run |
|---|---|
| Work on the app | stackctl, the terminal UI |
| Run a migration or a seed script | stackctl run api seed |
| Give an e2e suite a stack | startStack() in its global setup |
| Start the stack in a CI job | stackctl start --detach |
| Let a coding agent drive it | stackctl --headless and the control API |
They all get the same services, in the same order, with the same environment.
What it takes care of
- Start order and readiness. A service's
depsrun with it, and a dep withwait: trueholds it until that service's healthcheck passes. - Infrastructure. The databases and brokers in your
docker-compose.yamlcome up first, wait until healthy and run your migrations. See Infra. - Environment. Layered
.envfiles per workspace, service and mode, injected into each process, with the affected services restarted when a file changes. See Environment and modes. - Logs. Every service in one stream you can filter, with JSON logs formatted for reading and a log file per session. See Logs.
- Isolation between modes.
stackctl --mode testis a second session with its own ports, containers and state, next to the one you are working in. - Hostnames. An optional dev reverse proxy puts each service on its own host, with a status page while it is down.
- Clean exits. Quitting stops every service it started, and a second
stackctlin the same project takes over from the first instead of fighting it for ports.
What it leaves alone
- Your dev scripts. stackctl runs each service's own
devscript as written. Watching files and reloading stays with the tool that already does it (Vite,node --watch,air). - Your build. It builds nothing. How a service compiles, bundles or imports shared code is up to its own dev script.
- Your Compose file. Images, ports, volumes and healthchecks stay in
docker-compose.yaml. stackctl runs Compose for you and adds per-mode projects and callbacks around it. - Production. It is a development tool. Nothing in it deploys or serves real traffic.