Ship to prod before Kubernetes is worth it.
docker compose, but for prod — git-aware, multi-host, SSH-first. Build, push, pull, restart — in the right order, only what changed. One binary, one config, no cluster to babysit.
You know this.
You have three services on one VPS. To deploy, you SSH in, git pull, rebuild an image, docker compose up -d, then watch the logs and hope the new image actually came up. Every time.
kb-deploy run. Images built, pushed, pulled, restarted — in the right order, with health verified before moving on.
You changed one service but your deploy script rebuilds all of them, so a 2-minute fix takes 15 minutes to ship. Or you rebuild nothing and bring the wrong SHA to prod.
kb-deploy diffs against git and only touches the targets that actually changed. Everything else stays put.
Half your infra — the database, the cache, the broker — lives outside your app. Nothing manages them together. You bring them up with ad-hoc compose files that nobody maintains.
kb-deploy infra up brings the stateful layer up from the same deploy.yaml. One file, idempotent, no drift.
If you know docker compose, you already know kb-deploy.
Same mental model, same YAML shape, same up/down rhythm — but extended with the things compose intentionally doesn't do.
One file. Apps and infra together.
Put .kb/deploy.yaml in your repo. kb-deploy reads it and figures out what to build, what to push, and what to restart — over SSH, on the target host.
Same file is read by kb-monitor afterwards. Deploy and observe from one source of truth.
registry: ghcr.io/your-org
targets:
api:
path: apps/api
dockerfile: Dockerfile
host: prod-1
compose: infra/compose/api.yml
health: http://localhost:3000/health
web:
path: apps/web
host: prod-1
compose: infra/compose/web.yml
infrastructure:
postgres:
host: prod-1
image: postgres:16
volumes:
- /data/postgres:/var/lib/postgresql/data
redis:
host: prod-1
image: redis:7How it works
The things that matter once your deploys become routine.
Deploys only what changed
Affected targets are detected via git diff against the last deployed SHA. Nothing untouched rebuilds.
Builds, pushes, pulls, restarts — in order
Build on your machine or in CI, push to the registry, pull on the host, docker compose up. Each step is verified before the next.
Tracks last-deployed SHA per target
Every target remembers what it's currently running. status shows you the drift between HEAD and prod for each service.
Manages stateful infra alongside apps
Databases, caches, brokers — declared in the same deploy.yaml, brought up with infra up, idempotent, not duplicated.
SSH-first, no cloud account required
Runs over plain SSH with docker compose on the target. Works with any VPS. No cloud vendor, no API tokens, no control plane to configure.
Every command is scriptable
All commands support --json with structured output. Works in CI, in Makefiles, and in agent workflows. Failures carry hints.
Commands
All commands support --json for scripting and agent workflows.
kb-deploy runBuild and deploy affected targets (git diff against last deployed SHA).
kb-deploy run --allForce a full deploy of every target regardless of git state.
kb-deploy run kb-labs-webDeploy a specific target by name. Useful for hotfixes and targeted redeploys.
kb-deploy statusShow the last deployed SHA per target and whether each is in sync with HEAD.
kb-deploy listList every target configured in .kb/deploy.yaml, with their compose files and hosts.
kb-deploy infra upBring up stateful infra declared under infrastructure. Idempotent: running services are skipped.
kb-deploy infra statusShow runtime state of every stateful service on the host.
kb-deploy infra down <name>Stop and remove a specific infra service. Volumes are preserved unless you opt in.
Download
Pre-built binaries for macOS, Linux, and Windows. SHA-256 checksums included in every release.
Part of KB Labs
kb-deploy ships as a standalone binary and as part of the KB Labs platform. When you install KB Labs, kb-deploy is included automatically.
Install KB Labs →