On February 6, 2026, Heroku announced it was moving to a sustaining engineering model: stability, security, and reliability would continue, but no new features would ever ship again, and no new Enterprise contracts would be signed. Most migration coverage since has focused on the money — what it costs to stay versus what it costs to move. But there is a second kind of Heroku exit that has nothing to do with the invoice.
Some teams are leaving because of what the platform cannot do. A 30-second request timeout that kills long responses. Dynos that restart every 24 hours whether you like it or not. Two regions on standard plans, all on AWS, with your region locked in at app creation.
These were tolerable constraints when the platform had a future — every one of them looked like a roadmap gap that might close. The February announcement froze them in place permanently. What follows is the technical case to leave: each wall, the workload it breaks, and what self-hosting removes by construction.
The four walls, in one table
This is the whole argument on one screen. Each row is a constraint the freeze turned from a limitation into a permanent property.
| Wall | The exact limit | Workload it breaks | What a bigger bill buys | Self-hosted answer |
|---|---|---|---|---|
| 30-second router timeout | No first byte within 30s: the router returns an H12 error page while your app keeps burning compute, unknowingly. Not configurable. | LLM calls, SSE streams, report generation, any long request | Nothing — identical on every dyno type, Eco through Performance and Private Spaces | Your own timeout, your own config |
| Daily dyno cycling | Every dyno restarts at least once per 24 hours, plus up to 216 minutes of jitter; local disk is wiped. Deploys and config changes reset the clock. | Open WebSockets, in-memory sessions and caches, local files | Nothing — hits every dyno type including one-off dynos | Restarts on your schedule, persistent volumes |
| Two-region map | Common Runtime offers us and eu only (AWS N. Virginia and Ireland); region is immutable after app creation; everything runs on AWS | EU residency beyond Ireland, APAC and LatAm latency, region choice | Private Spaces adds Heroku regions — but they are still AWS regions. AWS-only and region immutability persist at every price. | Machines wherever you want them; residency is a street address |
| No free floor | Free dynos were removed in November 2022; the cheapest way to exist on the platform is now a paid dyno | Prototypes, side projects, the try-before-you-buy funnel | Nothing to buy back — the floor is paid and frozen | Idle cost is hardware you already own |
With the summary on the table, here is the evidence behind each row: the mechanics, what breaks, what the standard workarounds cost, and what changes when you own the machines.
The 30-second wall
Heroku's router gives your app 30 seconds to produce the first byte of a response. Miss the deadline and the router serves the client an error page and logs an H12 request timeout — while your application, unaware anything happened, keeps working on the abandoned request. Heroku's own documentation recommends setting an application-level timeout well under the limit, around 10 or 15 seconds. The timeout value itself is not configurable. It has been this way for over a decade, and the freeze means it will be this way indefinitely.
In 2026 this limit bites harder than it used to, because the workloads teams actually run have gotten slower. A decade ago the canonical victim was the long report query. Today it is the LLM call that takes 45 seconds to synthesize an answer, the server-sent-events stream that goes quiet while a pipeline stage runs, the agent loop that reasons in five silent gaps.
Practitioners keep rediscovering this the hard way: one team watched the router cut an SSE stream mid-pipeline because each model call was legitimately silent longer than the router allows; another saw profile generation fail because the browser received the router's HTML error page instead of JSON and reported "we couldn't reach the server" for a request the dyno was still processing.
The standard workaround is architectural: move slow work to a worker dyno, return immediately, and have the client poll for completion. That works, but price what it costs. You now run a worker formation, a queue or polling endpoint, client-side retry logic, and failure handling for jobs whose HTTP context is long gone — all to route around a number in someone else's router config. It is a reasonable pattern for genuinely background work. It is pure tax when the work is only "background" because 30 seconds was not enough.
And crucially, no amount of spending changes the number. The timeout is identical on a $5 Eco dyno, a $25 Standard dyno, a Performance dyno, and a Private Spaces dyno. There is no tier, add-on, or support ticket that raises it. Self-hosting removes it by construction: the timeout is whatever your reverse proxy says it is, and your reverse proxy answers to you.
The daily restart
Every Heroku dyno is restarted — cycled, in the platform's terminology — at least once every 24 hours, plus up to 216 random minutes of jitter so an app's whole formation does not bounce simultaneously. Deploys and config-var changes reset the 24-hour clock, which means busy apps restart far more often than daily. Each restart wipes the local filesystem. Cycling applies to all dynos, including one-off dynos.
Heroku designed this deliberately: dynos are meant to be stateless and disposable, and forced cycling keeps operators honest about that contract. For a textbook twelve-factor app with all state in Postgres or an external store, the daily bounce is invisible. The problem is how many real applications are not textbook twelve-factor apps.
The casualties are specific and predictable. Open WebSocket connections are severed mid-conversation — every real-time feature needs reconnection logic not as an edge case but as a daily event. In-memory sessions, caches, and rate-limit counters evaporate on someone else's schedule; anything you kept in process memory for speed must either move to an external store (another add-on, another bill, another latency hop) or accept random amnesia.
Local files — uploads awaiting processing, generated artifacts, SQLite databases — are deleted unless they were already copied somewhere durable. Teams learn to build around all of this, and the building-around becomes permanent scaffolding in the codebase.
No plan exempts you. Cycling hits every dyno type on every tier; it is a property of the dyno manager, not a quota you can upgrade past. When you own the machines, restarts happen on your schedule — for kernel upgrades and maintenance windows you chose — and persistent volumes mean a restart does not mean amnesia. The scaffolding comes down.
The two-region map
Heroku's Common Runtime offers exactly two regions: us and eu, mapping to AWS regions in N. Virginia and Ireland. You choose at app creation and you cannot change afterward — moving regions means creating a new app and migrating data. Everything underneath is AWS; the platform API itself reports the provider as amazon-web-services. Wider geography exists, but only behind Private Spaces, Heroku's enterprise tier with its own isolated network per space.
Three different teams hit this wall three different ways. The EU team with data-residency obligations gets one answer — Ireland — on standard plans. If a customer contract names Frankfurt, or a regulator asks where exactly tenant data rests, "Heroku's EU region" is the beginning of an uncomfortable conversation, not the end of one. Compare the self-hosted answer, which one migration writeup put memorably: "our database is on a server in Falkenstein, Germany" ends the discussion.
The APAC or LatAm team serves users a quarter-planet from the nearest dyno, with the latency that implies, unless it pays the Private Spaces toll. And the team that picked us at creation in 2019 and now needs eu discovers the choice was load-bearing and permanent.
Private Spaces genuinely helps with region count — but notice what money cannot buy even there. Every additional region is still an AWS region. There is no GCP region, no Azure region, no bare-metal region, no "our own datacenter" region. The AWS-only property persists at every price, as does region immutability after creation. On a living platform, "only two standard regions" reads as a gap the roadmap might fill. On a frozen platform it is the final geography.
Self-hosting inverts the whole model. Regions are wherever your machines are: a Hetzner box in Falkenstein for the German contract, one in Virginia for US users, one in Singapore when APAC latency matters. No tier gate stands between you and the map.
Frozen means forever
Each of the four walls predates the freeze by years. The timeout has been 30 seconds for over a decade. Daily cycling is older still. The two-region map and the AWS-only substrate are architectural, not incidental. And the free tier has been gone since November 2022, when Salesforce removed it citing fraud and abuse — a decision that broke trust with an entire generation of developers who had learned to build on Heroku's free dynos and never came back as paying customers.
Before February 2026, every one of these constraints shared a redeeming quality: the platform that imposed it was still being developed. A timeout that never changed might change. A region map with two pins might gain a third. That possibility — however faint after years of underinvestment — was doing real work in stay-versus-go decisions. Teams could rationally tell themselves that the constraint they were routing around was a roadmap item, not a tombstone.
The sustaining announcement removed that possibility in a single paragraph. No new features means the timeout never becomes configurable, cycling never becomes opt-in, the region map never grows, and the free floor never returns. These are not limitations anymore; they are the specification. Planning around them is no longer "waiting for the platform to improve" — it is designing for a platform that has finished changing.
Who should still stay
Honesty requires the counter-cases, because the technical argument to leave is strong but not universal. Teams deeply embedded in Salesforce — Heroku Connect syncing to Salesforce objects, AppLink, Agentforce integrations — may find the switching cost genuinely exceeds the constraint cost; the platform's frozen state does not unplug those pipes. Strictly stateless twelve-factor apps that respond in milliseconds, keep nothing in memory, and serve users near Virginia or Ireland may never touch any of the four walls — for them the freeze changed little.
And some teams will rationally keep paying the zero-ops premium while treating Heroku as a deprecating asset with an exit date. The mistake is not staying. The mistake is staying without a date, on a platform whose limits are now load-bearing walls rather than scaffolding.
But if your exit is technical rather than financial — if you are reading this because an H12 log line, a severed WebSocket, or a residency questionnaire sent you here — know that these constraints are choices your infrastructure made, not laws of nature. A request timeout is a config value. A restart schedule is a policy. A region map is a shopping list. They only feel immutable because someone else owns the machines underneath them.
Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own, with your timeouts, your restart policy, and your region map. Star the repo on GitHub or deploy your first app today.



