Here's a workflow most of us just accept: you spin up your local stack with a docker-compose.yml, and then, to actually ship it, you reach for a completely different toolchain. Helm charts, raw manifests, a GitOps controller, whatever your platform team standardized on. Two representations of the same application, maintained by hand, drifting apart the moment someone's in a hurry.
I wanted one tool the whole way. The same definitions that bring up my dev environment should also deploy it to staging and prod. Different target, same config.
Compose your environment from a catalog
The piece that makes this pleasant is a catalog of service presets. Instead of copy-pasting a Postgres block between six repos, someone curates it once, and you compose your environment out of building blocks:
export default defineEnvironment({
services: {
db: use("postgres"), // from the catalog
cache: use("redis"),
api: { build: "./api", dependsOn: ["db", "cache"] },
},
});
use("postgres") pulls a curated preset, and your own services sit right next to it. A platform team maintains the catalog (a file, an HTTP endpoint, or an OCI artifact), and developers assemble environments from it. There's even a small visual builder for this. You drag presets onto a canvas, wire up dependencies, and export the config. But the point is the model: shared building blocks, composed locally.
Then the same command runs everywhere:
kaupang up market # locally, docker compose
kaupang up market --target prod # prod, swarm or kubernetes, same config
Locally it's Compose. In prod the target says "Swarm" or "Kubernetes" and the same environment renders to that backend. You stop maintaining two truths.
The reason it can be one tool: it's a push tool, not a reconciler
Every modern deploy tool wants to be a control loop. Argo, Flux, the operator pattern. You install an agent, hand it your desired state, and let it reconcile forever. It's a genuinely great model when you need it. It's also a lot of standing machinery, and we've quietly accepted it as the only serious way to ship.
But a control loop can't be your docker compose up. You're not going to run an always-on reconciler to bring up your dev stack. The reason one tool can stretch from your laptop to production is that it doesn't reconcile:
Run it, it acts once, it exits.
No agent, no drift detection, no control loop. That's what makes it identical on a laptop and on a CI agent. The only thing that changes is the ambient target (context, env, secrets). The same property that makes it a good local dev tool is what makes the prod path trustworthy: it's deterministic, and it's the same code path you've run a hundred times locally.
Deploy like you build: resolve once, pin, replay
Because it acts once, a deploy can be treated like a build artifact instead of a living system:
- Images resolve to digests at deploy time, so "latest" can't change under you between staging and prod.
- Config pins to a bundle, a portable, content-addressed artifact you can carry into an airgap.
- Every run is recorded in an append-only ledger, so you can replay a deploy or roll back to a known-good snapshot.
It leans on the tools you already have. It shells out to docker, kubectl, and oras rather than reimplementing a registry client or a compose engine. Less surface area, fewer surprises.
When you do want a reconciler
I'm not claiming push beats GitOps. They solve different problems. If you're running a large multi-team fleet where continuous drift-correction is the whole job, a reconciler earns its keep. But there's a long tail of services where you don't want a standing agent. You want to run a deploy, know exactly what happened, and be able to roll it back. And for those, having the same tool from compose up to production removes a surprising amount of friction.
Try it
npm i -g @kaupang/cli
kaupang studio --catalog ./catalog.json # the visual builder, on :8080
# then:
kaupang up market
It's early and mostly a solo project, but every backend path (Compose, Swarm, Kubernetes) is exercised end-to-end against real Docker and a kind cluster in CI, not mocked. Code and docs: https://github.com/kaupang-dev/kaupang
I'd love to hear where you land on this. Is a curated service catalog plus one deploy tool from dev to prod something you'd actually want, or does the reconciler model already cover it for you?

Top comments (0)