There's a version of this question that sounds like a tech debate but is actually a question about your team's operational capacity. Docker Compose and Kubernetes both run containers. The difference is everything else: what happens when a container crashes, how you roll out updates, how you handle secrets, how you scale, and critically โ how much cognitive overhead you're willing to carry.
We've deployed infrastructure for Studio clients at both ends of this spectrum: small teams on a single VPS running Compose stacks, and multi-node Kubernetes clusters for organisations with dedicated ops capacity. The answer isn't "Kubernetes is better" โ it's "Kubernetes is appropriate when the operational complexity it introduces is less than the operational complexity it solves." That threshold is higher than most people assume.
What Compose is actually good at
Docker Compose gets dismissed as "not production-ready" by people who've never had to debug a Kubernetes misconfiguration at 2am. For the right deployment profile, Compose is excellent:
- Single-node deployments. If your workload fits on one machine โ and most small-team self-hosted stacks do โ Compose is the right tool. You get process isolation, network namespacing, volume management, and environment-specific config through
.envfiles. That's most of what you need. - Human-readable configuration. A
docker-compose.ymlis legible to any engineer who's spent a day with Docker. You can hand it to a new team member and they can understand the deployment in an hour. The equivalent Kubernetes manifests for the same stack are three to five times longer and require familiarity with a dozen resource types. - Fast iteration.
docker compose up -d --build service-nameis one command. No image push to a registry, no pod rollout to wait for, no rolling update strategy to configure. - Low dependency surface. Compose has one runtime dependency: Docker. Kubernetes has etcd, the API server, the scheduler, the controller manager, kubelet, kube-proxy, a CNI plugin, and usually a cloud provider integration or bare-metal load balancer. Every dependency is a failure mode.
The 47Network Studio deploys the Keycloak, Vault, and Matrix stacks for smaller clients on Compose with a systemd service for restart-on-failure and a daily backup cron. It's boring, it works, and operations staff who've never used Kubernetes can maintain it.
When Compose starts to strain
Compose has genuine limitations that become pain points as deployments grow:
- Multi-node workloads. Compose doesn't orchestrate across multiple hosts. Docker Swarm does, but Swarm's development has effectively stalled. If your workload needs to span machines for capacity or redundancy, you need a real orchestrator.
- Zero-downtime deployments. Compose's rolling update story is weak. Recreating a container means a brief downtime. You can work around this with blue-green deployments and a Nginx/Caddy reload, but it's manual and fragile at scale.
- Health-based scheduling. Compose will restart a crashed container, but it won't move it to a different host if the host is degraded, and it won't make sophisticated scheduling decisions based on resource availability.
- Secret management at scale. Compose reads secrets from environment variables or files. For a few services this is manageable; for twenty services across multiple stacks it becomes a configuration sprawl problem. Kubernetes Secrets (with external secrets operators) are more structured, and the Vault integration is better.
What Kubernetes actually gives you
Works well when...
- Single-server deployment
- Team under ~10 engineers
- No dedicated ops/platform role
- 5 or fewer services to orchestrate
- Acceptable: brief downtime on deploys
- Backup/restore is primary DR strategy
Worth the overhead when...
- Multi-node, multi-AZ required
- Someone owns the platform full-time
- GitOps (Argo CD/Flux) is a priority
- 15+ services with distinct scaling needs
- Required: zero-downtime rolling deploys
- Fine-grained RBAC on cluster resources
Kubernetes gives you a declarative control plane, automatic bin-packing, self-healing (restart, reschedule, replace failed pods), horizontal pod autoscaling, rolling deployments with configurable strategies, and a rich ecosystem of operators for databases, certificates, secrets, and more. These are real capabilities. The question is whether your operational context requires them.
The hidden cost people underestimate is ongoing cognitive load. A Kubernetes cluster requires someone to understand the networking model (CNI, Services, Ingress, NetworkPolicy), the storage model (PV, PVC, StorageClass), the scheduling model (Nodes, Taints, Tolerations, Resource Requests/Limits), the security model (RBAC, ServiceAccounts, PodSecurityAdmission), and the upgrade path. This knowledge has to live somewhere in your team. If it lives in one person's head, you have a bus factor problem. If it lives in nobody's head, you have an incident waiting to happen.
The Compose production checklist
If you decide Compose is right for your deployment, these are the gaps you need to fill that Kubernetes would have handled automatically:
- Process supervision: Wrap your
docker compose up -din a systemd service withRestart=alwaysandRestartSec=10. This ensures the stack comes back after a reboot or an unexpected Docker daemon restart. - Health checks: Define
healthcheckblocks in your Compose file for every service. Without them, Docker considers a container "healthy" as soon as it starts โ even if the process inside is still initialising or has crashed into a retry loop. - Secrets hygiene: Use Docker secrets or a bind-mounted secrets directory rather than plain environment variables in the Compose file. Env vars in Compose files end up in process listings and are visible to any process in the container.
- Backup automation: Kubernetes doesn't back up your data either, but operators make it easier to think about. In Compose land, write an explicit backup script for every persistent volume and test the restore procedure. Daily. Tested monthly.
- Log aggregation: Container logs go to Docker's JSON logging driver by default, which has no rotation by default. Configure log rotation (
max-size,max-file) or ship logs to a central store (Loki, Elasticsearch) before the disk fills up. - Image pinning: Pin image tags.
postgres:latestin production is a disaster waiting to happen when a major version update breaks your schema migrations silently.
The intermediate option: For multi-node deployments that aren't ready for full Kubernetes complexity, consider Nomad (HashiCorp's lighter orchestrator) or a managed Kubernetes service (k3s for bare metal, EKS/GKE/AKS for cloud) where the control plane is managed for you. Managed Kubernetes removes the "maintaining etcd" problem which is the most operationally demanding part of self-hosted Kubernetes.
A practical decision table
| Scenario | Recommendation | Reasoning |
|---|---|---|
| Solo developer, side project | Compose | Kubernetes is several orders of magnitude more operational overhead than a side project warrants. |
| 5-person startup, single server, <10 services | Compose | Invest ops time in your product. A solid Compose + systemd + Loki stack is maintainable by anyone on the team. |
| 20-person org, self-hosted internal tools, no dedicated ops | Compose or k3s | Compose for simplicity; k3s if you need multi-node or have one engineer who's comfortable owning it. |
| 50-person org, mixed workloads, one platform engineer | Managed K8s | One engineer can own a managed cluster. They shouldn't own a self-hosted control plane solo. |
| 100+ people, compliance requirements, multiple services teams | Kubernetes | The RBAC, audit logging, and multi-team isolation features of Kubernetes justify the overhead at this scale. |
| Any size, HA requirement, zero-downtime deploys mandatory | Kubernetes | Compose can't do this cleanly. If the SLA requires it, bite the Kubernetes complexity bullet. |
How 47Network ships both
Every 47Network product ships with both a Docker Compose file and Helm charts. This isn't fence-sitting โ it's an honest acknowledgment that different clients have different operational contexts. A 12-person NGO self-hosting Matrix should use the Compose file. A 200-person company with a platform team running Argo CD should use the Helm chart with GitOps.
Both deployment paths are first-class. The Compose files are tested in CI. The Helm charts are tested in CI. If a bug only reproduces on one of them, that's a bug we fix. Self-hosting support means both options actually work, not just the one we find more interesting to build.
When Studio clients ask which to use, we start with their team size, ops capacity, and whether they have โ or want โ a dedicated platform engineer. The answer follows from those constraints, not from what's technically more impressive to deploy.