Why Does My Heroku App Take 30 Seconds to Load: Dyno Sleep, Boot Time, and the Router Timeout

Farouk Ben. - Founder at OdownFarouk Ben.()
Why Does My Heroku App Take 30 Seconds to Load: Dyno Sleep, Boot Time, and the Router Timeout - Odown - uptime monitoring and status page

Your Heroku app takes thirty seconds to load because its Eco dyno went to sleep after thirty minutes without web traffic, and the first request has to wait for the dyno to wake and the application to boot. The wake itself is fast, usually a few seconds. Almost all of the delay you are measuring belongs to your own application starting up, and if the total crosses thirty seconds the request does not slow down, it dies.

This article separates the three things people mean when they say a Heroku app is slow to load, explains what Heroku's platform actually guarantees at each stage, covers the fixes that work and the one that quietly costs you money, and closes on why the problem is invisible until somebody outside your team hits it first.

What dyno sleeping actually is

Heroku's Eco dyno plan costs five dollars a month for a thousand dyno hours shared across every Eco dyno on the account, and the economics only work because the dynos sleep. Heroku's documentation is specific about the trigger: when an Eco web dyno receives no web traffic in a thirty minute period, it sleeps, and an Eco worker dyno on the same app sleeps alongside it. Sleeping dynos do not consume hours from your pool. Apps running only a worker dyno never sleep, because they never receive web requests, and they will drain your monthly allowance while nobody is watching.

The important detail is what happens on the way back. When a sleeping dyno receives traffic and the account still has hours available, it becomes active again after a short delay. Heroku describes this as a short delay for the first request with subsequent requests performing normally, and in practice the platform side of that wake is measured in seconds rather than tens of seconds. If your users are waiting half a minute, the dyno finished its job long before they finished waiting.

Where the other twenty five seconds go

The rest of the delay is your application booting, and it is entirely yours. A Rails or Django app loading its framework, reading environment configuration, establishing a database connection pool, warming a cache, compiling assets that were not precompiled at build time, and running any initializer that reaches across the network can spend twenty seconds before it is ready to answer anything. Nothing about Heroku makes this slower than it would be elsewhere. Sleep simply exposes a boot time you never noticed, because on a dyno that never sleeps it happens once at deploy.

There is a hard ceiling on this. Heroku's router terminates any request your application has not answered within thirty seconds, returning an error page to the visitor and an H12 request timeout in your logs. The limit is not configurable. An app whose cold boot lands close to that line does not merely feel slow, it fails intermittently, succeeding at twenty eight seconds and erroring when a slow database handshake pushes it to thirty two. If your users report a mix of long waits and errors on the same URL, you are watching the boot time cross that boundary rather than watching two separate bugs.

The fixes, in the order worth trying

Measure the boot before you buy anything. Run heroku logs with the tail flag while you request a sleeping app, and read the timestamps between the dyno starting and your framework reporting it is listening. That number tells you whether you have a platform problem or an application problem, and it is almost always the latter.

Cut the boot path. Precompile assets during the build rather than at boot, make database and cache connections lazy so the process can accept a request before every dependency is warm, and move anything calling an external API out of the initializer chain. Shaving a cold boot from twenty five seconds to eight changes the experience more than any plan upgrade.

Move to a dyno that does not sleep. A Basic dyno runs continuously and costs seven dollars a month against Eco's five. For anything a customer or another service touches, the two dollar difference is not a real decision.

Be careful with keep-alive pings. Hitting your own app every twenty minutes to prevent sleep does work, and Heroku's own documentation notes that monitoring services can have exactly this effect on a web dyno. It also converts a sleeping app into a permanently running one, which consumes your Eco hours around the clock. A single dyno kept awake for a full month burns roughly seven hundred and forty of your thousand hours, and when the pool is exhausted every Eco dyno on the account is forced to sleep for the rest of the month. You have not avoided the problem, you have rescheduled it to the worst possible date.

Why nobody notices until a customer does

Cold starts are structurally invisible to the people who build the app. Developers hit their own application constantly during the working day, so their dyno is almost never asleep when they visit. The thirty second load is reserved for the person arriving at nine in the morning, the client checking a demo link on a Sunday, or the partner service that calls your API twice a day.

This is the case for watching the app from outside rather than trusting the experience you have from inside it. An external check that measures response time on every request shows the cold start as a spike with a recognisable shape: one slow response, a run of fast ones, then another spike after a quiet period. That pattern is the signature of dyno sleep, and it is the evidence you need to decide whether the two dollar upgrade is worth it. Our guide to page load time covers the general version of the problem and which numbers actually matter to users.

Common mistakes in diagnosing Heroku cold starts

Blaming Heroku for the whole delay. The platform wakes the dyno in seconds. If the page takes half a minute, the application is spending that time booting, and no amount of support tickets will change it.

Upgrading the dyno without measuring first. A Basic dyno removes sleep, but an app with a twenty five second boot is still a twenty five second boot after every deploy and every restart. Fix the boot, then decide about the plan.

Adding a keep-alive ping and forgetting the hours. Pinging an Eco dyno awake around the clock consumes most of the monthly pool, and running out forces every Eco dyno on the account to sleep until the month rolls over.

Testing only from your own machine during work hours. Your dyno is awake because you keep waking it. The cold start belongs to the first visitor after a quiet period, which is never you.

Mistaking H12 timeouts for a separate bug. A boot that lands near thirty seconds will sometimes finish and sometimes trip the router timeout. Intermittent errors on a slow-loading route usually mean one problem, not two.

FAQ

How long does a sleeping Heroku dyno take to wake up?

The dyno wake itself is a short delay, typically a few seconds. What users experience as a much longer wait is the application's own boot time running after the dyno starts, which is entirely dependent on your framework, dependencies, and initializers.

Do all Heroku dynos sleep, or only some?

Only Eco dynos sleep. Basic, Standard, and Performance dynos run continuously. An Eco web dyno sleeps after thirty minutes without web traffic, and an Eco worker dyno on the same app sleeps with it.

Can I stop my Heroku app from sleeping without upgrading?

You can keep it awake by sending it traffic at least every thirty minutes, but the dyno then consumes Eco hours continuously, and exhausting the monthly pool forces every Eco dyno on the account to sleep. Upgrading to a Basic dyno is usually the cheaper answer.

Why does my Heroku app sometimes error instead of loading slowly?

Heroku's router terminates any request not answered within thirty seconds and emits an H12 request timeout. A cold boot landing close to that limit will succeed on fast attempts and fail on slow ones, which reads as an intermittent bug.

Closing thought

The thirty second Heroku load is rarely a Heroku problem. It is a boot time that was always there, made visible by a plan that stops paying for idle time, and made costly by a router that will not wait forever. Measure the boot, shorten it, and then decide whether sleep is a feature or a liability for the particular app in front of you. The answer is different for a staging environment than it is for anything a customer will ever open.

The harder part is knowing it is happening at all, because the people best placed to notice are the least likely to experience it. Odown checks your app from seventeen locations around the world on the interval you choose, records response time on every check, and tells you when a page that answered in four hundred milliseconds yesterday took twenty eight seconds this morning. If you want checks running against your Heroku app from outside your own browsing habits, website monitoring starts at twelve dollars a month with a fourteen day trial and no card required.