Why I Still Ship Docker Compose in Production (And When I Finally Quit)
Most small teams adopt Kubernetes because they think they have to. They see the industry standard, they see the job postings, and they assume that staying on Docker Compose is a sign of technical immaturity. It isn’t. For a team of fewer than three developers managing a single-node application with predictable load, Kubernetes is not a solution; it is a liability.
The reality of running a small team is that every hour spent managing control planes, storage classes, and ingress controllers is an hour not spent building product. A single well-provisioned cloud VM with Docker Compose handles the vast majority of pre-product-market-fit applications. Adopting orchestration before you have a genuine scaling problem is a common strategic mistake that costs significant engineering time and operational complexity.
Before you even consider migrating, you must ensure your Docker Compose environment is production-grade. If you are still hardcoding configuration or storing secrets in your repository, you are not ready for Kubernetes, and you are not ready for production. This guide outlines how to make Docker Compose resilient, when to stop resisting the hype, and how to execute a staged migration if and when you actually outgrow a single VM.
The Case for Docker Compose in Production
The decision to use Docker Compose in production is not about rejecting modern tooling; it is about matching the complexity of your tooling to the complexity of your problem. For small teams, the hidden costs of orchestration are often underestimated. These costs are not just financial (the cost of the cluster itself) but operational: the time spent debugging networking issues, managing certificate rotations, and maintaining the orchestration layer itself.
Docker Compose remains the right choice when your architecture fits on a single node, your team is small, and your load is stable. According to the SFEIR Institute, a team of fewer than three developers with stable load patterns should stay on Compose. The operational overhead of Kubernetes only becomes justified when you need automatic scaling, high availability SLAs (99.9%+), or a microservices architecture that requires independent deployment cycles.
Until those conditions are met, a single $50/month VPS with Docker Compose can serve 90% of pre-product-market-fit startups. This approach saves an estimated 15-25 hours per week in engineering time compared to managing a Kubernetes cluster. That is time that can be reinvested into feature development, customer acquisition, or simply keeping the lights on. The goal is to prove you have outgrown VMs before adopting Kubernetes, not to adopt it because it is trendy.
The Pre-Kubernetes Checklist: Making Compose Production-Ready
If you are staying on Docker Compose, you must treat it as a production system. Many teams make the mistake of treating Compose as a development-only tool and then trying to patch it for production later. This is a failure mode that leads to security vulnerabilities and downtime. Before you declare your Compose stack production-ready, you must address the following critical areas.
Resource Limits: Preventing Noisy Neighbors
One of the most common mistakes in Docker Compose configurations is missing resource limits. Without constraints, a single service can consume all available CPU and memory on the host, causing other services to crash or become unresponsive. You must set CPU and memory constraints for every service in your docker-compose.yml. This ensures that if one service has a memory leak or a spike in traffic, it does not take down the entire application.
Healthchecks: Automated Recovery
Docker Compose does not automatically restart services if they become unresponsive; it only restarts them if the container process exits. You must implement liveness and readiness probes for every service. A liveness probe checks if the service is alive, while a readiness probe checks if it is ready to accept traffic. Without these, you risk routing traffic to a service that is still initializing or is stuck in a broken state. Automated recovery based on health checks is essential for maintaining uptime without manual intervention.
Secrets Management: Keeping Credentials Safe
Storing secrets in your repository is a critical security failure. Credentials, API keys, and database passwords should be stored outside the repository, typically in environment files that are gitignored or in a dedicated secrets manager. Furthermore, you must have a process for rotating these secrets when personnel changes occur. If a developer leaves the company and their credentials are still in the environment, you have a security breach. AppMaster emphasizes that storing secrets outside the repo and rotating them is a minimum safe approach for any production environment.
Backups: Protecting Your Data
Docker volumes are ephemeral by default. If the host machine fails, your data is gone unless you have a backup strategy. You must document and test volume backup procedures for databases and user uploads. This is not optional. If you are running a database in a container, you need a clear plan for how that data is persisted and backed up. Raff Technologies highlights that externalizing databases is a key part of a production-grade path, but if you do keep them in Compose, backups are non-negotiable.
Monitoring: Knowing When Things Break
You cannot manage what you cannot measure. Setting up monitoring is critical for understanding the health of your application. You need alerts for uptime, disk space, and service health. Without monitoring, you will only know your service is down when your customers tell you. Tools like Prometheus and Grafana can be integrated into a Docker Compose stack to provide visibility into resource usage and service status.
Common Pitfalls and How to Avoid Them
Even with a solid checklist, teams often fall into traps that undermine their production stability. These pitfalls are often subtle but have significant consequences.
Hardcoded Configuration
Hardcoding configuration values in your Dockerfiles or docker-compose.yml files is a major anti-pattern. Configuration should be externalized using environment variables. This allows you to change settings without rebuilding images and makes it easier to manage different environments. Distr.sh outlines this as a common mistake, recommending that teams build a reference docker-compose.yml and document all environment variables clearly.
Ignoring Staging Environments
Building a staging environment that mirrors production is critical to avoid “it works on my machine” issues. If your staging environment differs from production in terms of resource limits, network configuration, or service versions, you will encounter bugs in production that were not present in staging. AppMaster stresses the importance of a staging environment that matches production to ensure that what you test is what you deploy.
Over-Engineering with Helm
For small teams, diving into Helm charts and complex orchestration manifests is often over-engineering. Helm is a powerful tool, but it adds a layer of complexity that is not justified until you have multiple environments and a need for templated deployments. Stick to simple docker-compose.yml files until you have a clear need for more advanced orchestration.
Database Mistakes
Putting stateful services like databases inside the cluster early on adds significant complexity. You have to manage storage classes, StatefulSets, and persistent volume claims. Raff Technologies and AppMaster both advise keeping stateful services external to the cluster early on. Use managed database services from your cloud provider or run databases on separate VMs. This simplifies your Compose stack and reduces the risk of data loss.
When to Finally Make the Switch to Kubernetes
There comes a point when Docker Compose is no longer sufficient. This is not a failure of Compose, but a success of your application. You should consider migrating to Kubernetes when you need automatic scaling, high availability SLAs, frequent deployments, or a microservices architecture.
Signs It’s Time
The decision to switch should be driven by specific operational needs. If you are manually scaling your infrastructure, if you are experiencing downtime due to single points of failure, or if your deployment process is too slow to keep up with development, it is time to look at Kubernetes. SFEIR Institute provides a decision checklist for staying on Compose versus migrating to K8s, emphasizing that the switch should be made when the pain of staying on Compose outweighs the cost of adopting K8s.
The Staged Migration Path
Do not try to migrate everything at once. A staged migration path reduces risk and allows you to learn Kubernetes incrementally. Raff Technologies suggests externalizing databases first, then uploads, and then splitting workers. This allows you to validate your Kubernetes setup with stateless services before tackling the complexity of stateful data.
Conversion Tools: Kompose as a Starting Point
Automatic conversion tools like Kompose can generate a starting point for your Kubernetes manifests, but they do not produce production-ready configurations. These tools often miss critical details like resource limits, health checks, and security contexts. You must manually adapt the generated files to meet production standards. SFEIR Institute warns that Kompose produces starting points, not final solutions, and emphasizes adding native K8s elements like resource limits and health checks.
Audit Your Stack Today
Docker Compose is a valid and powerful production strategy for small teams. It allows you to move fast, reduce operational overhead, and focus on building your product. The key is to treat it with the same rigor as any other production tool. Follow the checklist, avoid common pitfalls, and only migrate to Kubernetes when you have a genuine need for it.
The goal is not to avoid Kubernetes forever, but to avoid adopting it prematurely. Prove you have outgrown VMs before adopting Kubernetes. Build simple, scale when it hurts, and keep your engineering time focused on what matters: your customers and your product.
Audit your docker-compose.yml for resource limits today. If you find none, add them. If you find secrets in the file, move them to a .env file and update your .gitignore. These are the small, concrete steps that separate a hobby project from a production system.
Sources and further reading
- Kubernetes vs Docker Compose for Small Teams | Raff
- Docker Compose vs Kubernetes: A Practical Decision Guide for Software Distribution | Distr
- Docker Compose vs Kubernetes: a checklist for small apps | AppMaster
- Docker vs Kubernetes in 2026: When to Use Each (With Decision Chart)
- Docker Compose vs Kubernetes: When to Switch to Orchestration | SFEIR Institute
Find more practical writing from the RodyTech archive.
RodyTech publishes practical writing on AI systems, infrastructure, and software that teams can actually ship. Use the archive paths below to keep reading by topic or browse the full library.
- Browse the full archive by publication date and topic
- Hands-on notes from real builds, deployments, and ops work
- Category paths for AI, infrastructure, developer tools, and security
No comments yet