Fly.io vs Heroku
A comparison of Fly.io and Heroku built from values read directly from each provider's own documentation, with the source recorded against every figure.
The short answer
- Pick Fly.io if
- Workloads that ship as Docker images and need placement in particular regions. Billing is purely usage-based with no plan tiers, which suits spiky or region-pinned traffic better than a flat monthly fee.
- Pick Heroku if
- Teams that want to deploy by pushing to Git and let the platform handle the runtime, with Postgres, a scheduler and Docker deploys available on the same platform.
10 sourced criteria separate them:
- Pricing model
- Fly.io: Usage-based, no compute plan tiers
- Heroku: Usage-based on wall-clock time, prorated to the second
- When you exceed a cap
- Fly.io: No plan cap to exceed — Fly bills per second for provisioned resources. The only documented enforcement is unspecified automated scaling limits, which surface as an error message (platform-wide, all plans)
- Heroku: Service sleeps: on the Eco plan ($5/month for a 1000 dyno-hour pool, the cheapest paid tier) exhausting the pool forces every Eco dyno on the account to sleep for the rest of the month, and extra hours cannot be bought
- Memory (entry plan)
- Fly.io: 256MB on shared-cpu-1x, the smallest Machine size ($2.02/month at the Amsterdam-region rate shown in the pricing table)
- Heroku: 0.5 GB RAM on the Eco dyno ($5 flat/month, the cheapest paid dyno) and 0.5 GB on the Basic dyno ($7/month)
- File or inode limit
- Fly.io: 8 GB rootfs (deployed image) limit per Machine, platform-wide on all plans; exceeding it fails the image push at deploy time
- Heroku: 1000 MB maximum compressed slug size, platform-wide on all plans; raisable via support ticket
- Streaming response limit
- Fly.io: No duration or size ceiling documented. Streaming works, but Fly Proxy buffers responses before compressing them, so progressive server-side rendering needs Content-Encoding: none set on those responses.
- Heroku: Platform-wide (router): 30 seconds to send the first byte, then a rolling 55-second idle window — if no data is sent for 55 seconds the connection is terminated
- Managed connection pooling
- Fly.io: Supported
- Heroku: Limited
- Scheduled jobs
- Fly.io: Limited
- Heroku: Supported
- Persistent storage
- Fly.io: Supported
- Heroku: Not supported
- Scales to zero
- Fly.io: Supported
- Heroku: Limited
- Regions
- Fly.io: 18 regions
- Heroku: 2 regions on the Common Runtime, which is what a standard dyno runs in: eu (Europe) and us (United States). A further 10 — Dublin, Frankfurt, London, Montreal, Mumbai, Oregon, Singapore, Sydney, Tokyo and Virginia — exist only in Private Spaces, an Enterprise product.
Pick the criteria you care about. The chart counts how many of them lean toward each provider — the same read as scanning the bars below, just totalled for the ones you chose.
Fly.io 0
Heroku 0
At a glance.
| Criterion | Fly.io | Heroku |
|---|---|---|
| Pricing | ||
| Pricing model | Usage-based, no compute plan tiers | Usage-based on wall-clock time, prorated to the second |
| When you exceed a cap | No plan cap to exceed — Fly bills per second for provisioned resources. The only documented enforcement is unspecified automated scaling limits, which surface as an error message (platform-wide, all plans) | Service sleeps: on the Eco plan ($5/month for a 1000 dyno-hour pool, the cheapest paid tier) exhausting the pool forces every Eco dyno on the account to sleep for the rest of the month, and extra hours cannot be bought |
| Limits | ||
| Memory (entry plan) | 256MB on shared-cpu-1x, the smallest Machine size ($2.02/month at the Amsterdam-region rate shown in the pricing table) | 0.5 GB RAM on the Eco dyno ($5 flat/month, the cheapest paid dyno) and 0.5 GB on the Basic dyno ($7/month) |
| File or inode limit | 8 GB rootfs (deployed image) limit per Machine, platform-wide on all plans; exceeding it fails the image push at deploy time | 1000 MB maximum compressed slug size, platform-wide on all plans; raisable via support ticket |
| Execution | ||
| Streaming response limit | No duration or size ceiling documented. Streaming works, but Fly Proxy buffers responses before compressing them, so progressive server-side rendering needs Content-Encoding: none set on those responses. | Platform-wide (router): 30 seconds to send the first byte, then a rolling 55-second idle window — if no data is sent for 55 seconds the connection is terminated |
| Managed connection pooling | Supported | Limited |
| Deployment | ||
| Docker deployment | Supported | Supported |
| Scheduled jobs | Limited | Supported |
| Infrastructure | ||
| Persistent storage | Supported | Not supported |
| Managed databases | Supported | Supported |
| Scales to zero | Supported | Limited |
| Autoscaling | Limited | Limited |
| Regions | 18 regions | 2 regions on the Common Runtime, which is what a standard dyno runs in: eu (Europe) and us (United States). A further 10 — Dublin, Frankfurt, London, Montreal, Mumbai, Oregon, Singapore, Sydney, Tokyo and Virginia — exist only in Private Spaces, an Enterprise product. |
Where they differ.
Pricing model
- Fly.io
- Usage-based, no compute plan tiers
- Heroku
- Usage-based on wall-clock time, prorated to the second
Sources (2) →Sources ↓
- Fly.io pricing ↗
“Plans get complicated, so we just charge based on usage. Billing is based on the resources provisioned for your apps, pro-rated for the time they are provisioned.”
Read 2026-09-05 · official docs
- Usage & Billing | Heroku Dev Center ↗
“Heroku computes usage from wall-clock time, not CPU time. Any dynos scaled above 0 accrue usage, regardless of traffic or activity. Heroku prorates all costs to the second.”
Read 2026-09-05 · official docs
When you exceed a cap
- Fly.io
- No plan cap to exceed — Fly bills per second for provisioned resources. The only documented enforcement is unspecified automated scaling limits, which surface as an error message (platform-wide, all plans)
- Heroku
- Service sleeps: on the Eco plan ($5/month for a 1000 dyno-hour pool, the cheapest paid tier) exhausting the pool forces every Eco dyno on the account to sleep for the rest of the month, and extra hours cannot be bought
Sources (2) →Sources ↓
- Fly.io Resource Pricing · Fly Docs ↗
“Organizations may be subject to automated scaling limits to prevent abuse or to help with capacity planning. Email the address in the error message if you run into such a limit and it's getting in your way.”
Read 2026-09-05 · official pricing
- Eco Dyno Hours | Heroku Dev Center ↗
“When you use all your Eco dyno hours for a given month, all Eco dynos on your account are forced to sleep for the rest of the month. You can't purchase additional dyno hours.”
Read 2026-09-05 · official docs
Memory (entry plan)
256MB on shared-cpu-1x, the smallest Machine size ($2.02/month at the Amsterdam-region rate shown in the pricing table)
0.5 GB RAM on the Eco dyno ($5 flat/month, the cheapest paid dyno) and 0.5 GB on the Basic dyno ($7/month)
Sources (2) →Sources ↓
- Fly.io Resource Pricing · Fly Docs ↗
“shared-cpu-1x | 1 shared | 256MB | $0.00000078 | $0.0028 | $2.02”
Read 2026-09-05 · official pricing
- Dyno Types | Heroku Dev Center ↗
“Eco | 0.5 GB | 1x | 1x-4x | $5 flat* | N/A | No | ✔”
Read 2026-09-05 · official docs
File or inode limit
- Fly.io
- 8 GB rootfs (deployed image) limit per Machine, platform-wide on all plans; exceeding it fails the image push at deploy time
- Heroku
- 1000 MB maximum compressed slug size, platform-wide on all plans; raisable via support ticket
Sources (2) →Sources ↓
- Troubleshoot your deployment · Fly Docs ↗
“Machines have an 8GB rootfs limit.”
Read 2026-09-05 · official docs
- Limits | Heroku Dev Center ↗
“The default maximum allowed slug size (after compression) is 1000 MB.”
Read 2026-09-05 · official docs
Streaming response limit
- Fly.io
- No duration or size ceiling documented. Streaming works, but Fly Proxy buffers responses before compressing them, so progressive server-side rendering needs Content-Encoding: none set on those responses.
- Heroku
- Platform-wide (router): 30 seconds to send the first byte, then a rolling 55-second idle window — if no data is sent for 55 seconds the connection is terminated
Sources (2) →Sources ↓
- Content Encoding — Fly Docs ↗
“The proxy buffers responses before compressing them. That can break HTML streaming—e.g., progressive server-side rendering. To avoid buffering, disable compression by setting Content-Encoding: none for those responses”
Read 2026-09-05 · official docs
- Request Timeout | Heroku Dev Center ↗
“Heroku supports HTTP features such as long-polling and streaming responses. An application has an initial 30 second window to respond with a single byte back to the client. However, each byte transmitted thereafter (either received from the client or sent by your application) resets a rolling 55 second window. If no data is sent during the 55 second window, the connection will be terminated.”
Read 2026-09-05 · official docs
Managed connection pooling
- Fly.io
- Supported
- Heroku
- Limited
Sources (2) →Sources ↓
- Cluster configuration options ↗
“All Managed Postgres clusters come with PGBouncer for connection pooling, which helps manage database connections efficiently. You can configure how PGBouncer assigns connections to clients by changing the pool mode.”
Read 2026-09-05 · official docs
- Server-Side Connection Pooling for Heroku Postgres | Heroku Dev Center ↗
“Server-side connection pooling is available for Standard, Premium, Private, and Shield-tier databases. [...] Server-side connection pooling isn't available for Essential-tier databases.”
Read 2026-09-05 · official docs
Scheduled jobs
- Fly.io
- Limited
- Heroku
- Supported
Sources (2) →Sources ↓
- fly machine run · Fly Docs ↗
“Use the --schedule flag to set the Machine's config.schedule property, which starts the Machine on a fuzzy hourly, daily, weekly, or monthly cycle.”
Read 2026-09-05 · official docs
- Heroku Scheduler | Heroku Dev Center ↗
“Scheduler is a free add-on for running jobs on your app at scheduled time intervals, much like cron in a traditional server environment.”
Read 2026-09-05 · official docs
Persistent storage
- Fly.io
- Supported
- Heroku
- Not supported
Sources (2) →Sources ↓
- Fly Volumes overview · Fly Docs ↗
“Fly Volumes are local persistent storage for Fly Machines.”
Read 2026-09-05 · official docs
- Dynos (App Containers) | Heroku Dev Center ↗
“Each dyno gets its own ephemeral filesystem, with a fresh copy of the most recently deployed code. During the dyno's lifetime, its running processes can use the filesystem as a temporary scratchpad, but no files that are written are visible to processes in any other dyno.”
Read 2026-09-05 · official docs
Scales to zero
- Fly.io
- Supported
- Heroku
- Limited
Sources (2) →Sources ↓
- Automatically stop and start Machines · Fly Docs ↗
“Use autostop/autostart to automatically start and stop or suspend existing Machines based on incoming requests. [...] you don't pay for their CPU and RAM when they're in a stopped or suspended state.”
Read 2026-09-05 · official docs
- Eco Dyno Hours | Heroku Dev Center ↗
“If an app has an Eco web dyno, and that dyno receives no web traffic in a 30-minute period, it sleeps. In addition to the web dyno sleeping, if you have a worker Eco dyno, it also sleeps. Eco web dynos do not consume Eco dyno hours while sleeping.”
Read 2026-09-05 · official docs
Regions
18 regions
2 regions on the Common Runtime, which is what a standard dyno runs in: eu (Europe) and us (United States). A further 10 — Dublin, Frankfurt, London, Montreal, Mumbai, Oregon, Singapore, Sydney, Tokyo and Virginia — exist only in Private Spaces, an Enterprise product.
Sources (2) →Sources ↓
- Fly.io regions ↗
“You can host your apps in any of the following regions — including ams (Amsterdam, Netherlands), nrt (Tokyo, Japan) and syd (Sydney, Australia).”
Read 2026-09-05 · official docs
- Regions | Heroku Dev Center ↗
“eu Europe Common Runtime us United States Common Runtime dublin Dublin, Ireland Private Spaces frankfurt Frankfurt, Germany Private Spaces london London, United Kingdom Private Spaces montreal Montreal, Canada Private Spaces mumbai Mumbai, India Private Spaces oregon Oregon, United States Private Spaces singapore Singapore Private Spaces sydney Sydney, Australia Private Spaces tokyo Tokyo, Japan Private Spaces virginia Virginia, United States Private Spaces”
Read 2026-09-05 · official docs
Which should you choose?
Choose Fly.io if…
Workloads that ship as Docker images and need placement in particular regions. Billing is purely usage-based with no plan tiers, which suits spiky or region-pinned traffic better than a flat monthly fee.
Editorial · Palash Bagchi · approved
Choose Heroku if…
Teams that want to deploy by pushing to Git and let the platform handle the runtime, with Postgres, a scheduler and Docker deploys available on the same platform.
Editorial · Palash Bagchi · approved
Consider something else if…
- Fly.io: You want a predictable flat bill rather than charges that track the resources provisioned for each app.
- Heroku: The dyno filesystem is ephemeral, and a web process must respond within 30 seconds of receiving a request.
Documented by only one.
These criteria are published by one provider and not the other. An absence here means we have not found a source, not that the feature is missing.
Questions this comparison answers.
When you exceed a cap: Fly.io or Heroku?
Fly.io: No plan cap to exceed — Fly bills per second for provisioned resources. The only documented enforcement is unspecified automated scaling limits, which surface as an error message (platform-wide, all plans)
Heroku: Service sleeps: on the Eco plan ($5/month for a 1000 dyno-hour pool, the cheapest paid tier) exhausting the pool forces every Eco dyno on the account to sleep for the rest of the month, and extra hours cannot be bought
Should I choose Fly.io or Heroku?
Pick Fly.io if Workloads that ship as Docker images and need placement in particular regions. Billing is purely usage-based with no plan tiers, which suits spiky or region-pinned traffic better than a flat monthly fee.
Pick Heroku if Teams that want to deploy by pushing to Git and let the platform handle the runtime, with Postgres, a scheduler and Docker deploys available on the same platform.
