New article weekly. No noise. Subscribe

When Not to Use Kubernetes for a Small Team: Lessons in Avoiding Premature Complexity

Kubernetes can solve real problems. But for small teams, its complexity often costs more than it returns. In our case, the real cost wasn’t infra. It was lost product capacity.

Kubernetes is often treated as the default “serious” infrastructure choice. If you are building something ambitious, the thinking goes, you should probably be using it.

For a small engineering team, that can be exactly wrong.

In a small team, infrastructure complexity can become a tax on product development long before it becomes leverage.

That was the lesson I learned the hard way.

Why the choice looked reasonable

The original decision did not come from chasing fashion. It looked defensible.

Microservices felt flexible. Kubernetes looked future-proof. Scaling sounded prudent. If the system grew, the architecture would already be ready.

That logic is easy to understand, especially early on when requirements still feel uncertain and growth is mostly imagined in terms of what might happen later.

The problem is that future-proofing often imports the operational burden of a future you do not actually have yet.

With hindsight, I would not have started with either Kubernetes or microservices.

Where the complexity showed up

The cost did not come from one dramatic failure. It came from accumulated friction.

Debugging deployments was expensive. Operational knowledge concentrated in too few people. CI/CD became brittle. Local development drifted further from production. Internal tooling grew around the cluster. And some of the abstractions introduced to manage that complexity added more of it.

We used OpenTofu and Terragrunt, for example, which helped with configuration sprawl but also increased the overall complexity budget.

That was the recurring pattern: introduce tooling to manage complexity, and sometimes increase total complexity instead.

None of these problems alone would have justified rethinking the architecture.

Together, they imposed a real tax.

The real cost was lost product capacity

This was the part that mattered most.

The biggest problem was not operational overhead. It was what that overhead displaced.

Every hour spent maintaining infrastructure, debugging deployments, or helping new joiners climb the learning curve was an hour not spent shipping product.

That has business impact.

For a resource-constrained team, product capacity is often the scarcest resource you have. Spending too much of it feeding infrastructure is not an abstract engineering tradeoff. It changes what the team can actually build.

That is where the architecture stopped being “technically sophisticated” and started becoming a drag.

The problems Kubernetes solved were mostly not our problems

This is the uncomfortable part.

We were carrying solutions for problems we largely did not have.

We did not meaningfully need Kubernetes-level autoscaling. We did not need sophisticated scheduling. We did not need advanced rollout machinery. We did not need much of the operational surface we were maintaining.

We started with one client. We now have three.

That does not justify carrying the complexity budget of infrastructure designed for a very different scale.

And if those requirements had arrived later, we could have evolved toward them.

Complexity does not have to be front-loaded.

What I would do instead

If I were making the same architectural call again, I would start much simpler.

A monolith.

Docker Compose for dependencies.

Let the architecture grow with actual requirements rather than guessed ones.

That does not mean “never use Kubernetes.” It means earn the right to use Kubernetes by first having the problems it is good at solving.

Complexity should arrive as a response to constraints, not as a prediction about future ones.

That is a much safer default for small teams.

The lesson I took from it

Kubernetes was not really the mistake in isolation.

Premature complexity was.

For a small engineering team, Kubernetes becomes a bad tradeoff when the operational complexity it introduces exceeds the product and scaling problems it actually solves.

That was true in our case.

And it is the question I would ask much earlier now, before adopting any infrastructure that looks mature, powerful, and just a little too ready for a future that has not happened yet.

If you're still here, might as well subscribe :)

· RSS

Related Articles