Run a Docker Compose stack with a health gate
You want Runyard to start your backend stack via docker compose up, mark it as running only once your API responds, and properly shut everything down when you click Stop.
The trick
Two gotchas trip people up.
- Two CLIs, same name.
docker compose(the V2 plugin, two words) is the current syntax. The standalonedocker-composebinary (hyphenated) is legacy and increasingly missing on fresh installs. Use the V2 plugin. - SIGTERM does not clean up. Runyard's default shutdown sends SIGTERM to
docker compose up, then SIGKILL after a grace period. That stops the foregroundcomposeprocess but leaves your containers running in the background. You need an explicitstopCommandsentry that runsdocker compose downso containers, networks, and volumes are torn down properly.
Working configuration
{
"name": "Backend Stack",
"type": "service",
"directory": "~/Code/your-project",
"autoStart": false,
"startCommands": [{
"label": "Compose",
"command": "docker",
"args": ["compose", "up"],
"startupCheck": "http://localhost/api/health",
"startupFallbackPort": 8000,
"startupRequestTimeout": 30
}],
"stopCommands": [{
"label": "Compose down",
"command": "docker",
"args": ["compose", "down"]
}],
"paths": ["/opt/homebrew/bin", "/Applications/Docker.app/Contents/Resources/bin"]
}
Replace the directory, the health URL path, and the fallback port with your own values.
Why this works
docker compose up(without-d) keeps Compose attached to your terminal. Runyard tracks its PID and considers the service alive while Compose is running.startupCheckpolls your API endpoint. The port is auto-detected from Compose's stdout when it prints something likeListening on 0.0.0.0:8000. If detection misses (some Compose versions print port info via a sub-process Runyard can't trace),startupFallbackPortis used.startupRequestTimeout: 30gives slow containers (databases, migrations, etc.) time to come up before each probe attempt fails.stopCommandsrunsdocker compose downinstead of relying on SIGTERM. This stops all services in the compose file, removes the default network, and is the only safe way to tear down a stack.- The
pathsarray ensuresdockerresolves on a fresh shell. Adjust if you use OrbStack (/Applications/OrbStack.app/Contents/MacOS/xbin) or Colima.
Prerequisites
- Docker Desktop, OrbStack, or Colima already running. Runyard does not start the Docker daemon for you.
- A
docker-compose.yml(orcompose.yml) at the project directory. - A health endpoint in your application. If your app does not have one, you can use a TCP probe instead by replacing
startupCheckwith whatever fallback fits your stack, or use a separatehealthChecktool.
Gotchas
- If your
compose.ymlusesrestart: unless-stopped, containers come back on next Runyard launch. Either setrestart: "no"for dev, or accept that you'll see "already running" warnings. docker compose down -v(with-v) deletes named volumes. Do not add-vto the stop command unless you're certain you want to wipe data each time.- If port detection fails consistently, set
startupFallbackPortto the host-side port (left side of8000:8000in your compose file), not the container-side port.