Skip to main content

The $3,000-to-$200 Migration Story Cuts Both Ways: What a Kubernetes-to-Fly.io Bill Drop Really Proves

10 min readDora NodaDora Noda
Share
On this page

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 itemMonthly costWhat it really is
EKS control plane$73AWS list price: $0.10/hour per cluster, before a single pod runs
Worker nodes (5× m6i.2xlarge-class, on-demand)~$1,550Sized 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~$280Two NAT gateways at ~$33 each plus $0.045/GB processing; the load balancer floor
EBS volumes, snapshots, container registry~$220Grows monotonically; nobody deletes a snapshot
Egress (500 GB at ~$0.09/GB)~$270AWS data transfer, the line nobody forecasts
Observability + incident tooling (Datadog-class seats)~$600Priced 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 itemMonthly costBasis
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~$30Volumes at $0.15/GB, IPv4 at $2
Egress (100 GB at $0.02/GB)~$2Plus the workload got lighter under measurement
Built-in metrics, no per-host agent bill$0The Datadog line simply doesn't transfer
Headroom for growth (spare machines, stopped)~$25Billed 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 itemFly.io (disciplined)Owned Hetzner (disciplined)
Compute for web + workers~$102 (6 small machines)on-box
Postgres + Redis + volumes~$71self-run, on-box
Egress (~100 GB)~$2included (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:

VariableWhat changesWho wins instead
K8s already right-sized (VPA + autoscaling + spot)The (a)+(b) buckets shrink to near zero; the delta collapses to the unit-price sliceStays 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 ~$135Owned 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 wayWhoever has the cheapest database tier, not the cheapest machines
Multi-region / spiky-to-zeroPer-second billing and scale-to-zero only exist on the metered sideFly.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.

Related articles

Check your move before you migrate

Free browser tools: check a render.yaml or your Render scripts against bex, or turn a Heroku app or docker-compose.yml into a draft render.yaml. Nothing you paste leaves your browser.

Open the migration tools