Services
A service is a long-running dev process: an API, a frontend, a worker. To stackctl it is a directory with a dev entry point, plus a key in stackctl.config.ts.
The dev script
stackctl looks in the service's directory:
- With a
package.json, it runs thedevscript. - With a
Makefileand nopackage.json, it runsmake dev.
That is how a Node service and a Go service sit side by side:
// apps/api/package.json
{
"name": "api",
"scripts": {
"dev": "node --watch src/index.ts"
}
}# apps/worker/Makefile
.PHONY: dev
dev:
@go run .A service's other scripts (build, test, seed, …) are not part of its lifecycle. They show up in the terminal UI's commands menu, and sctl run runs one from a shell.
To run a script with another name, set command:
worker: { command: 'start' }, // runs the `start` script or targetAfter a code edit
stackctl does not watch your source. Whether a service picks up an edit depends on its own dev script, and command says which kind it is:
command | The dev script… | After you edit its code |
|---|---|---|
'dev' (the default) | watches files and reloads | nothing to do |
['start', { watches: false }] | runs once, from current source | restart it |
Restart a service with r in the terminal UI, sctl service restart -s <name>, or POST /command/service/restart/<name> on the control API. watches changes nothing about how the service runs: it tells you, and a coding agent, whether a restart is needed.
An edit to a service's .env files is different: stackctl watches those and restarts the service itself.
Dependencies
deps lists the services that run alongside this one. Add wait: true to hold it until that service's healthcheck passes:
services: {
api: { port: 3001, healthcheck: '/health' },
web: { port: 3000, deps: [{ service: 'api', wait: true }, 'worker'] },
worker: {},
}Selecting web runs api and worker too, and web starts once api is healthy. See deps.
How a script is run
stackctl runs a package.json script itself: the script's text goes to /bin/sh in the service's directory, with no package manager in between. A Makefile target runs as make <name>.
PATHstarts with the service'snode_modules/.bin, then each parent directory's, so a script can name a binary installed in the service or at the workspace root.- The environment is the service's resolved
.envfiles, itsPORT, and the usualnpm_package_name,npm_lifecycle_eventandINIT_CWD. pre<name>andpost<name>scripts are not run. Put the step in the script:"dev": "node codegen.ts && vite dev".- Package manager script settings have no effect (pnpm's
scriptShell,shellEmulator, …). - Exit codes are reported as they are. A script killed by a signal reports 128 plus the signal number (
137forSIGKILL).
Shared code
A library several services import is not a service, and is not in the stackctl config: stackctl never builds or runs it. How services import shared code is up to the project. An edit to a library reaches a service the way an edit to its own code does: its dev script picks it up, or the service is restarted.