Getting started
stackctl runs a monorepo's services during development. You describe them once in a typed config file; stackctl starts the ones you pick and the services they need, brings up their infrastructure, loads their environment, and shows it all in one terminal UI.
The same config drives a headless mode for tests and CI and for coding agents.
Requirements
- Node.js 26.12.1 or newer.
- macOS or Linux. Windows is not supported.
- Docker with Compose v2, only if the config declares infra.
Install
pnpm add -D stackctlnpm install -D stackctlyarn add -D stackctlThis installs two commands, stackctl and its short alias sctl. They are the same program: sctl is the one to type, and the one this guide uses. A script or a CI file spells out stackctl.
stackctl sets the project up as it installs: in a project with no config, that is sctl init --yes (below). It is skipped in CI and never fails an install. pnpm runs a dependency's install script only once you allow it: run pnpm approve-builds.
Set up the project
pnpm sctl initinit is interactive and safe to run again. It:
- Asks whether to install the agent skill (recommended).
- Creates
stackctl.config.tsat the repo root. An existing config is left alone. - Adjusts the root
tsconfig.jsonso the config type-checks.
Pass -y to accept the defaults without questions.
Describe your services
stackctl.config.ts is the one file you write and commit:
import { defineConfig } from 'stackctl';
export default defineConfig({
serviceRootDir: 'apps', // each service lives at apps/<name>
services: {
api: {
// read from api's .env files, and given to the process as PORT
port: ({ envs }) => Number(envs.API_PORT),
healthcheck: '/health', // probed at http://localhost:<port>/health
},
web: {
port: 3000,
// selecting web also runs api, and holds web until api is healthy
deps: [{ service: 'api', wait: true }],
// links in the footer
urls: [
'', // web's own address, shown as "web ↗"
'/docs', // a path on it
{ label: 'storybook', url: 'http://localhost:6006' }, // any URL, with a label
],
},
},
});The key is the service's name. Most options take a plain value or, like port above, a callback over the service's environment, so the config can follow your .env files instead of repeating them.
Each service needs one thing in its own directory: a dev script in its package.json, or a dev target in a Makefile for a service in another language.
// apps/api/package.json
{
"name": "api",
"scripts": {
"dev": "node --watch src/index.ts"
}
}See Services for how a service is run, and the config file for every option.
Run it
pnpm sctlPick the services to run, press ⏎, and the terminal UI takes over: one combined log, with every service's state in the footer.
To skip the picker, name the services: pnpm sctl -s web.
A complete example
The example/ monorepo in the stackctl repo is a small working project: a Node API, a Go worker run through a Makefile, a web frontend, a Postgres database and a mail catcher from docker-compose.yaml, and the dev reverse proxy in front. Its stackctl.config.ts shows most options in use, with comments.
Next steps
- Why stackctl: what it replaces.
- Environment and modes:
.envfiles per service and per mode. - Infra: databases and other Compose services.
- Tests and CI: the same stack for an e2e suite.
- CLI reference: every command and flag.