When Docker Swarm still makes sense, and when it starts costing too much
Choosing an orchestrator is rarely about the technology. It comes down to how many people can fix it in the middle of the night, and how much your traffic fluctuates. This piece is my list of criteria, not a ranking of tools.
Who it’s forFor developers and tech leads on teams of up to a dozen or so people who run their own infrastructure and are wondering whether it’s “time for Kubernetes yet.”
Every few months, someone asks me why we don’t move everything to Kubernetes. It’s a fair question. The answer: for now, it wouldn’t pay off. Below I explain how I reach that conclusion and what would have to change for me to change my mind.
Where I start: who’s going to run it
The first question isn’t about the tool. It’s about people. How many people on the team understand the infrastructure well enough to diagnose an outage on their own? If the answer is “one, maybe two,” then every layer of abstraction I add is debt taken out in their name.
Swarm is built into Docker Engine. If you know docker compose, you’ll understand docker stack deploy in an afternoon. Kubernetes gives you much more, but it also demands much more: its own object model, its own tooling, its own way of thinking about networking and configuration.
Where Swarm works well
In my experience, Swarm is a sensible choice when three conditions are met:
- Traffic is predictable. You know roughly how many replicas each service needs, and you don’t have to add more automatically every few minutes.
- You run a handful of services, or a dozen or so, not hundreds. You can still read the stack file from top to bottom.
- The team is small and prefers simplicity over full control.
In that setup, you get what you actually need: rolling updates with automatic rollback, secrets, overlay networks, health checks and simple label-based routing through Traefik.
services:
api:
image: registry.example.com/api:1.42.0
deploy:
replicas: 3
update_config:
parallelism: 1
delay: 10s
order: start-first
failure_action: rollback
restart_policy:
condition: on-failure
labels:
- traefik.enable=true
- traefik.http.routers.api.rule=Host(`api.example.com`)
- traefik.http.services.api.loadbalancer.server.port=8080
healthcheck:
test: ['CMD', 'wget', '-qO-', 'http://localhost:8080/health']
interval: 10s
timeout: 3s
retries: 3
secrets:
- db_password
secrets:
db_password:
external: true
Two lines matter most here: order: start-first and failure_action: rollback. The new replica starts before the old one is stopped, and if the health check fails, Swarm rolls back to the previous version on its own. For most web applications, that’s enough to turn deploys into a non-event.
Where it starts to hurt
Swarm has its limits, and it’s worth knowing them before you hit them.
No autoscaling. There’s no equivalent of the Horizontal Pod Autoscaler. You can work around it with a script that reads metrics and changes the replica count, but then you’re maintaining your own autoscaler.
A smaller ecosystem. Many tools today are built with Kubernetes in mind: database operators, ready-made Helm charts, integrations with observability systems. With Swarm, you end up assembling things yourself more often.
Stateful services. You can run databases in Swarm, but it takes discipline: pinning them to specific nodes, well-planned volumes and backups. I usually keep them outside the cluster.
| Criterion | Docker Swarm | Kubernetes |
|---|---|---|
| Barrier to entry | Low, if you know Compose | High, a whole new set of concepts |
| Autoscaling | None built in | Built in (HPA, VPA) |
| Tooling ecosystem | Modest | Very large |
| Maintenance cost in a small team | Low | High |
| Flexibility as you grow | Limited | Very high |
How I record a decision like this
I record every decision of this kind in one place, together with the conditions under which it stops applying. That way, a year from now we don’t argue from scratch. We just check whether the conditions have changed.
- Decision
- We’re staying on Docker Swarm for the next 12 months.
- Why
- A small team, predictable traffic, a dozen or so services. Swarm covers our needs, and everyone on the team understands how it works.
- Costs
- No autoscaling and fewer ready-made tools. Some things (e.g., backups of stateful services) we put together ourselves.
- Revisit when
- we need per-service autoscaling, we expand into multiple regions, or the number of services no longer fits in a single stack file.
What this means
I’m not saying Swarm is better than Kubernetes. I’m saying that for many small teams it’s good enough, and the difference in maintenance cost is bigger than feature comparisons suggest.
If you’re weighing the same choice, start with three questions: who’s going to fix it, how much does your traffic fluctuate, and how many services will you have a year from now? The answers usually settle it faster than a feature table.
Sources and documentation
- Docker Docs: Swarm mode overviewdocs.docker.com
- Docker Docs: Deploy a stack to a swarmdocs.docker.com
- Traefik Docs: Swarm providerdoc.traefik.io