Docker Compose or Kubernetes: what you are actually buying
Stop debating — here is the decision framework based on your actual needs
One machine or many — everything else follows from that. The honest operational cost of Kubernetes, the middle options most comparisons skip, and the symptoms that mean you have genuinely outgrown Compose.

Docker Compose orchestrates containers on one machine. Kubernetes orchestrates them across many. Everything else — the complexity, the cost, the hiring implications — follows from that single difference.
The decision is usually framed as a technical comparison. It is really a question about your organisation: Kubernetes is a distributed system that you now operate in addition to your application, and that operational load is the actual price. Ask what you are buying with it.
The same application, both ways
# docker-compose.yml
services:
api:
image: myapp:1.4.2
ports: ["8080:8080"]
environment:
DATABASE_URL: postgres://db:5432/app
depends_on: [db]
restart: unless-stopped
db:
image: postgres:17
volumes: ["pgdata:/var/lib/postgresql/data"]
volumes:
pgdata:docker compose up -dThe same thing on Kubernetes needs a Deployment, a Service, a ConfigMap, a Secret, a StatefulSet for Postgres, a PersistentVolumeClaim, and an Ingress — roughly 150 lines across several files, before you have added TLS certificates, monitoring, or a way to deploy them.
That verbosity is not gratuitous. Each object exists because the system cannot assume the pieces share a machine. But if they do share a machine, you are paying for a generality you are not using.

Choose Compose when
- The application fits on one server, or a few servers you can treat independently.
- Nobody's job is "keep the platform running". Compose is operated by whoever is on call for the app.
- Vertical scaling still has room. A modern VPS goes to 64 cores and 256GB, which is a great deal of traffic.
- Brief downtime during a deploy is acceptable, or you can handle it with a second container and a proxy switch.
- You want a developer to be able to read the whole deployment definition in a minute.
Compose comfortably runs real production workloads — a single well-specified server handles far more traffic than most teams expect, and a great deal of profitable software runs this way.
Choose Kubernetes when
- You genuinely need to scale across machines, because one machine is not enough or because you cannot tolerate one failing.
- You are running enough services that manual placement has become a job in itself.
- Zero-downtime rolling deploys with automatic rollback are a requirement, not a preference.
- Multiple teams deploy independently and need namespaces, quotas and RBAC between them.
- You want the ecosystem — cert-manager, external-dns, Prometheus operators, service meshes — which is genuinely excellent and genuinely assumes Kubernetes.
- Someone owns the platform. This is the real gate.
The honest cost
Managed control planes have a published price; the rest does not. What to expect:
- A control plane fee from most managed providers, plus the nodes themselves.
- Node overhead. System components consume resources on every node before your workloads get any, and provider-reserved memory scales with instance size.
- The learning curve. A team new to Kubernetes spends months becoming fluent, and encounters CrashLoopBackOff, pending pods with no schedulable node, and OOMKills during that period.
- Upgrades. Kubernetes deprecates APIs on a schedule, and managed providers force upgrades. This is recurring work forever, not a one-off.
Against that, Compose's cost is a server and the deploy script you write once.
The middle ground
Managed Kubernetes (EKS, GKE, AKS) removes control-plane operation but not the rest. You still own node pools, upgrades, networking and RBAC. It lowers the floor; it does not remove it.
K3s and k0s are conformant Kubernetes in a single small binary. If your reason for wanting Kubernetes is the API and ecosystem rather than hyperscale, K3s on three modest servers gives you most of it for a fraction of the operational surface.
Docker Swarm gives you multi-node orchestration with Compose-like syntax. It is stable and still shipped, but it is maintained rather than developed — the ecosystem and hiring pool have moved elsewhere. Reasonable for an existing deployment; hard to recommend for a new one.
Nomad is a genuine middle option: multi-node scheduling, much simpler than Kubernetes, and it schedules non-container workloads too. Smaller ecosystem.
Managed container platforms — Cloud Run, Fly.io, Render, App Runner, ECS Fargate — remove orchestration entirely. For a stateless web service that needs to scale and survive a machine failure, this is frequently the right answer and it is skipped surprisingly often, because the comparison is framed as Compose versus Kubernetes with nothing in between.
Signals you have outgrown Compose
Not a schedule — a set of symptoms:
- You are running Compose on several servers and hand-maintaining which services sit where.
- You have written scripts to do rolling deploys, health-check gating and rollback. You are building an orchestrator.
- A single machine failure means real downtime and that is no longer acceptable.
- Vertical scaling has hit the largest instance available.
- Several teams need to deploy without coordinating.
Notably absent: service count. Fifteen services on one adequately sized machine is fine. Distribution is what forces the change, not decomposition.
Keeping the door open
Whichever you pick, these make the eventual migration straightforward, and they are good practice regardless:
- Configuration from the environment, never baked into images.
- Real health endpoints. Separate liveness (is the process wedged?) from readiness (can it serve traffic?). Compose barely uses the distinction; Kubernetes depends on it.
- Handle SIGTERM. Finish in-flight requests, close connections, then exit. Without this, every rolling deploy drops requests.
- Stateless application containers. State in a database or object store, never on a container's local disk.
- Logs to stdout, structured, no log files inside containers.
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/healthz"]
interval: 30s
timeout: 3s
retries: 3
start_period: 40sAn application built this way moves to Kubernetes as a translation exercise. One that is not will need reworking whatever you migrate to.
The recommendation
Start with Compose. Move when a specific symptom above forces you to, and when you know who will own the platform afterwards. Adopting Kubernetes ahead of need is the more common and more expensive mistake — it slows delivery for months in exchange for capabilities the team has no current use for.
And if the reason for wanting it is scaling a stateless web service, price a managed container platform first. It may remove the question entirely.


