Every few weeks, another version of the same post goes viral: a team migrates off Kubernetes onto Fly.io, the monthly bill falls off a cliff — $3,000 to $200, a 15x drop — and the moral is that per-use pricing beat paying for headroom. The genre peaked this spring with an April 2026 piece claiming a $47,340/month EKS bill rebuilt on Fly.io for $3,200 with the same performance. The numbers are always real. The attribution is where it gets interesting.
Because there are two completely different stories hiding inside every one of these migration posts. Story one: Fly.io's unit prices are dramatically cheaper than Kubernetes. Story two: the Kubernetes cluster was wildly over-provisioned, and the migration was the first time anyone actually measured what the workload needed. Only one of them is mostly true — and the answer cuts both ways, against Kubernetes maximalists and against the "just move to Fly.io" moral. Let's decompose the $3,000 into its parts and see which half of the 15x each platform actually earned.
The decomposition ledger: where the 15x actually comes from
Start with a representative $3,000 EKS bill for a small team — a handful of services, one Postgres, staging plus prod. Nothing exotic, and deliberately typical rather than pathological:
| Line item | Monthly cost | What it really is |
|---|---|---|
| EKS control plane | $73 | AWS list price: $0.10/hour per cluster, before a single pod runs |
| Worker nodes (5× m6i.2xlarge-class, on-demand) | ~$1,550 | Sized for peak-plus-safety-margin two years ago, never revisited |
| Unused requests on those nodes (~60% idle) | (inside the $1,550) | The headroom the cluster bills for and the workload never touches |
| ALB + NAT gateways + data processing | ~$280 | Two NAT gateways at ~$33 each plus $0.045/GB processing; the load balancer floor |
| EBS volumes, snapshots, container registry | ~$220 | Grows monotonically; nobody deletes a snapshot |
| Egress (500 GB at ~$0.09/GB) | ~$270 | AWS data transfer, the line nobody forecasts |
| Observability + incident tooling (Datadog-class seats) | ~$600 | Priced per host/container, so it scales with the over-provisioned node count |
| Total | ~$3,000 |
Now the same workload rebuilt the way the migration writeups describe it — measured first, then sized — on Fly.io's 2026 price list:
| Line item | Monthly cost | Basis |
|---|---|---|
| App machines (4× shared-cpu-2x, 4 GB) | ~$90 | ~$21–24 per machine-month; shared CPUs from ~$2 for the small ones |
| Worker machines (2× shared-cpu-1x, 1 GB) | ~$12 | ~$5.70 per machine-month |
| Managed Postgres Basic + 10 GB | ~$41 | $38 entry fee plus $0.28/GB storage — no hobby tier |
| Redis + volumes + dedicated IPv4 | ~$30 | Volumes at $0.15/GB, IPv4 at $2 |
| Egress (100 GB at $0.02/GB) | ~$2 | Plus the workload got lighter under measurement |
| Built-in metrics, no per-host agent bill | $0 | The Datadog line simply doesn't transfer |
| Headroom for growth (spare machines, stopped) | ~$25 | Billed by the second; stopped machines cost nothing |
| Total | ~$200 |
Here's the attribution the migration posts usually skip. Of the ~$2,800 delta:
- ~$1,400 (half the savings) is eliminated idle. The workload needed roughly 40% of what the nodes provided. That money wasn't buying Kubernetes; it was buying empty CPU. Any platform that forced a re-measurement would have recovered it.
- ~$900 (a third) is right-sizing plus de-tooling. Right-sized requests, a smaller Postgres than the RDS instance it replaced, and — quietly the biggest single line — the per-host observability bill collapsing when the host count did.
- ~$300 is AWS fixed infrastructure that doesn't transfer. NAT gateways, load balancer hours, and the steeper egress rate are real, but they're an AWS-topology tax, not a Kubernetes tax. A cluster on cheap bare metal never had them.
- ~$200 or less is Fly.io's unit-price advantage. Per-second billing on small shared-CPU machines genuinely beats on-demand EC2 for bursty services. It's real, it's just the smallest slice of the story.
Read that again: roughly 80% of the 15x comes from measuring the workload and deleting what it never used. The platform switch was the occasion for the savings, not mostly the cause of them.
Why Kubernetes bills inflate by default
This isn't a story about one careless team. The over-provisioning is structural, and 2026 data says it's getting worse. Cast AI's 2026 State of Kubernetes Optimization Report found 69% of clusters CPU-overprovisioned — up from 40% in 2024 — with memory overprovisioning even worse at 79%. The CNCF FinOps microsurvey found 49% of organizations saw cloud spend increase after migrating to Kubernetes, with 70% citing overprovisioning as the primary cause. Sysdig's usage research, summarized by ScaleOps, measured 69% of provisioned CPU cores going unused on average, estimating that a ~150-node fleet overspends by close to $1 million a year.
Three mechanisms do most of the damage, and all three are visible in the ledger above.
First, Kubernetes schedules by requests, not usage. A pod that requests 2 CPUs and uses 0.3 still occupies 2 CPUs of scheduling capacity, and the cluster autoscaler keeps nodes around to honor the sum of requests. Every post-incident "bump the requests to be safe" becomes permanent capacity. The requests ratchet only turns one way unless someone owns turning it back.
Second, the node pool is quantized and sticky. You buy whole nodes, the autoscaler is conservative about killing them, and staging namespaces hold production-shaped capacity around the clock. Idle shows up as utilized on every dashboard except the one nobody built: cost per actual request served.
Third, the ecosystem bills per host. Observability, security agents, and service-mesh sidecars frequently price by node or container — so the over-provisioned node count multiplies into the tooling bill. In our ledger, the $600 monitoring line is the purest example: it shrank in the migration not because Fly.io meters kindly, but because there were suddenly fewer hosts to meter.
None of this is an argument that Kubernetes is bad technology. It's an argument that Kubernetes gives you enough rope to hang a budget with, and that most teams hang first and measure later — usually during the migration post-mortem that becomes the viral post.
The uncomfortable follow-up: price the disciplined workload on owned hardware
Here's the part that cuts against the migration moral. If 80% of the savings came from right-sizing rather than from Fly.io's prices, then the disciplined workload — the measured one, the one that actually fits in $200 of Fly.io machines — should be priced a third way: on hardware you own. Same workload, same discipline, no meter:
| Line item | Fly.io (disciplined) | Owned Hetzner (disciplined) |
|---|---|---|
| Compute for web + workers | ~$102 (6 small machines) | on-box |
| Postgres + Redis + volumes | ~$71 | self-run, on-box |
| Egress (~100 GB) | ~$2 | included (20 TB-class allowance) |
| Platform / control plane | $0 (no seat fee) | $0 |
| The box itself | — | ~$45–55 (AX41-class dedicated: 6 cores, 64 GB, NVMe) |
| Total | ~$200 | ~$45–55 |
The owned-hardware row undercuts both cloud bills — not by a little, by roughly 4x against the already-optimized Fly.io number. That's the uncomfortable follow-up for both sides of the debate: the migration story proves right-sizing matters enormously, and right-sizing's logical endpoint isn't a smaller cloud bill, it's a flat hardware bill with the meter removed entirely.
Two honest caveats before anyone screenshots the table. First, the Hetzner row prices hardware, not operations — someone still runs Postgres backups, OS patches, and the 3 a.m. pages, and that labor is real whether it's your team or Fly.io's on-call. Our September ledger priced this same shape across five vendors and the conclusion held: self-hosted wins on invoice dollars and spends the difference in engineering time. Second, even the anchor repriced this year: Hetzner raised cloud prices up to ~3x on popular families for new orders on June 15, 2026 (Northflank's breakdown), so the flat row is flatter than metered rows, not frozen in time.
But the direction is unambiguous. The migration writeup's real finding was never "Fly.io is 15x cheaper than Kubernetes." It was "this team was buying 15x more infrastructure than its workload needed, and measuring it fixed that." Once you've done the measuring, the cheapest place to run the measured workload is hardware with no per-unit meter at all.
Sensitivity: when the story inverts
A single worked example proves a mechanism, not a universal ranking. Four variables can flip pieces of this story, and an honest version names them:
| Variable | What changes | Who wins instead |
|---|---|---|
| K8s already right-sized (VPA + autoscaling + spot) | The (a)+(b) buckets shrink to near zero; the delta collapses to the unit-price slice | Stays on Kubernetes; migration saves ~10–20%, not 15x |
| Egress-heavy (1 TB+/mo) | Fly.io's $0.02/GB slope adds ~$20/TB; Render-style $0.15/GB would add ~$135 | Owned hardware hardest to beat; its flat allowance doesn't move |
| Tiny stack (side project) | The $38 Managed Postgres floor dominates a $200 bill; compute is nearly free either way | Whoever has the cheapest database tier, not the cheapest machines |
| Multi-region / spiky-to-zero | Per-second billing and scale-to-zero only exist on the metered side | Fly.io genuinely wins — idle capacity you can switch off beats idle capacity you own |
The pattern across all four rows: the platform choice decides the shape of the bill (slope vs. step function, floor vs. meter), while right-sizing decides its size. Teams that skip the measuring step and switch platforms are optimizing the shape while ignoring the size — which is exactly backwards, since size was 80% of the money.
The decision rule
If your Kubernetes bill feels wrong, the migration stories are right about the first step and misleading about the second. The first step is an audit, not a migration: measure actual usage against requests, kill the idle nodes, look at what the per-host tooling costs on the hosts you don't need. Our September ledger's rule still applies — price the Postgres tier and the egress slope before you price the compute, because those lines decide the ranking more than any machine price.
Only then, with the disciplined workload in hand, compare platforms — and include the owned-hardware column, because the team that just proved it can run lean has already done the hard part of self-hosting. The $3,000-to-$200 story was never really about Fly.io beating Kubernetes. It's about measurement beating assumption, 15 to 1. The platform you measure on matters much less than the fact that you measured.
Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own, with flat-rate economics instead of a meter on every dimension. Star the repo on GitHub or deploy your first app today.



