Two winters ago I moved my side project onto Kubernetes. It was a Go API, a background worker, Postgres, and Redis, running happily under Docker Compose on one VPS. I’d been using Kubernetes at my day job for years and I told myself it would be cleaner: proper rolling deploys, health-based restarts, one way of doing things at work and at home.
I installed k3s on the same size of box, wrote the manifests, added an ingress controller and cert-manager, and moved the database onto a local persistent volume. It took about three weekends. Then it ran fine for five months, until a k3s upgrade and a cert-manager upgrade landed in the same week, and I spent a Saturday reading changelogs for software that existed only to run four containers I used to start with one command.
I moved back to Compose that night. That doesn’t mean Kubernetes is bad, or that no solo developer should touch it. It means I had used it to solve problems I didn’t have. So this piece is really about one question: at what point does Docker Compose actually stop being enough?
What Compose already does that people forget
A lot of “we outgrew Compose” stories are really “we didn’t know Compose could do that.” On a single machine, Compose gives you:
- Declarative config in a file. Services, networks, volumes, environment, all in one YAML you can commit.
- Restart policies.
restart: unless-stoppedbrings a crashed container back and brings everything up after a reboot. - Healthchecks and startup ordering.
depends_onwithcondition: service_healthywaits for the database to be ready before starting the app. - Resource limits. CPU and memory caps per service.
- Multiple replicas of a stateless service.
deploy.replicasworks for scaling on one host, behind a reverse proxy. - Profiles and override files for dev versus prod differences.
For one person running a web app, a worker, a database, and a cache, that covers almost everything you need day to day. The Kubernetes features I was excited about (self-healing, declarative state, health probes) were mostly things Compose already did on one host.

What Kubernetes costs a solo developer
The cost isn’t mainly money or RAM, though both are real. k3s is the lightweight option and it still wants several hundred megabytes before your apps start. Managed clusters are easier to run, and some providers charge for the control plane while others don’t, so check before you assume it’s free.
The real cost is the stack you now own:
- The cluster itself. Kubernetes ships a few minor releases a year and each is supported for a limited window. You will upgrade, and upgrades deprecate APIs your manifests use.
- An ingress controller to get HTTP traffic in, with its own config and upgrades.
- Certificate management, usually cert-manager, with its own custom resources.
- Storage. On a single node, persistent volumes are local disk with extra steps. You don’t get durability you didn’t have before; you get another abstraction to debug when a pod can’t mount its volume.
- More YAML. My Compose file was about 60 lines. The equivalent manifests were several hundred, before Helm.
- A debugging model with more layers. When something breaks, you check the pod, the deployment, the service, the ingress, the events, and the node. On Compose you check the container logs.
None of this is hard for someone who does it daily. It’s still work that doesn’t ship features, and when you’re the only developer, that time comes out of the product.
When Docker Compose stops being enough
Here’s the list I wish I’d written before those three weekends. These are the real limits, in the order most solo projects hit them.
1. You need more than one machine for the same service
This is the big one. Compose manages containers on one Docker host. If you need a service to run on two or more machines, for capacity or so that losing one box doesn’t take you offline, Compose on its own can’t schedule across them. You can run the same Compose file on two servers behind a load balancer, and plenty of people do, but then you are the scheduler: you deploy to each, you decide what runs where, you handle a box dying.
Kubernetes, or any real orchestrator, starts earning its keep exactly here: several nodes, workloads placed automatically, and pods rescheduled when a node disappears.
2. You need zero-downtime deploys, reliably
docker compose up -d with a new image stops the old container and starts the new one. For a few seconds, nothing is serving. For a side project, a few seconds at 2 a.m. is fine. For a product with paying customers in several timezones, it may not be.
You can get around this on Compose: run two replicas behind Caddy or Traefik and roll them one at a time, or use a tool that does blue-green on a single host. It works, but it’s a script you maintain. Kubernetes rolling updates with readiness probes do this by default. If zero-downtime deploys are a hard requirement and you’re already on more than one node, that’s a strong signal.
3. You need to scale on load, automatically
If traffic is spiky enough that you need to add capacity within minutes without being awake, that’s autoscaling, and it only matters if you have more than one machine to scale onto. On one VPS you’re limited by the box. Autoscaling across nodes is a real Kubernetes strength, though it’s rare for a solo project to need it before revenue makes hiring a possibility.
4. You have many services with independent release cycles
Four containers in one Compose file is easy to reason about. Fifteen services, each deployed on its own schedule, with their own config and secrets, starts to strain a single file and a single docker compose up. Kubernetes namespaces, per-service deployments, and a common deploy pipeline help. But if you’re one person with fifteen services, it’s worth asking whether you should have split into that many deployables before asking which orchestrator runs them.
5. Your platform requires it
Some things are only packaged as Helm charts or operators. Some customers or compliance setups expect you to run on a managed Kubernetes service. If an external requirement says Kubernetes, the decision is made.

Reasons that sound like limits but aren’t
I’ve heard all of these as reasons to move a solo project to Kubernetes. None of them hold up on a single host.
- “I need containers to restart when they crash.” Compose restart policies do that.
- “I need health checks.” Compose has them, and can gate startup on them.
- “I want infrastructure as code.” A Compose file in git is infrastructure as code.
- “I need secrets management.” An env file with tight permissions, or Docker secrets, covers most solo cases. Kubernetes Secrets are base64-encoded by default, not encrypted, unless you configure encryption at rest or add a tool for it.
- “It’ll be easier to scale later.” Moving from Compose to Kubernetes when you actually need to is a few days of work. Running Kubernetes for two years before you need it costs far more than those few days.
The middle ground
The gap between “one Compose file on one VPS” and “a Kubernetes cluster” is wider than people think, and most solo projects that outgrow the first should look here before jumping to the second:
- A bigger VPS. Vertical scaling is boring and effective. Doubling RAM and cores costs a few dollars a month and takes minutes.
- Two boxes, split by role. Database on one, app on the other, each with its own Compose file. You get isolation and some headroom with no orchestrator.
- Deploy tools built on Docker. Tools like Kamal handle zero-downtime deploys across a few servers over SSH, without a cluster.
- A PaaS. Fly, Render, Railway, or a self-hosted layer like Coolify. You give up some control and pay a markup, and someone else handles rolling deploys and multi-instance.
- Managed databases. Often the thing that actually keeps you up at night is Postgres, not the app. Moving the database to a managed service fixes backups and failover without touching how you run the app.
When a solo developer should use Kubernetes anyway
I’m not dogmatic about this. There are good reasons:
- You’re learning it for your career. Running a real app on a real cluster teaches you things tutorials don’t. Just be honest that the project is a learning environment, and don’t put your only income on it while you learn.
- You already operate it fluently and have a template. If you have a cluster, GitOps, and manifests you copy between projects, the marginal cost of one more app is small. The cost I paid was building all of that for one project.
- You genuinely hit limits 1 to 3 above. Multiple nodes, zero-downtime as a requirement, automatic scaling. At that point a managed cluster is a reasonable choice, and hand-rolling the same behavior on Compose is the thing you’d regret.
Where I landed
My project is back on Compose, on a slightly bigger VPS, with a managed Postgres. Deploys cause about four seconds of downtime, which I schedule for the quietest hour and nobody has ever noticed. Backups are the database provider’s problem. The whole server config is a Compose file, a Caddyfile, and a short deploy script.
If I ever need a second app server, my first step will be a load balancer and the same Compose file on two boxes. If I need that to heal itself when a box dies, or to scale without me, that’s when I’ll set up a cluster again. It’ll be a managed one, and I’ll have a concrete reason for it this time.