comparison

Why Heroku Metrics Are Not Uptime Monitoring (And What Heroku Apps Need Instead)

Heroku is one of the most developer-friendly platforms on the internet. You push code, Heroku runs it. You don't think about servers, you don't manage infras...

Heroku is one of the most developer-friendly platforms on the internet. You push code, Heroku runs it. You don't think about servers, you don't manage infrastructure, and you can be in production in minutes. But there's a gap most Heroku developers discover only after their first production incident: Heroku's built-in observability tells you what's happening inside your dynos, not whether your app is actually reachable by your users.

This article explains exactly what Heroku provides, what it doesn't, and why external uptime monitoring like Vigilmon is a required addition for any production Heroku application.


What Heroku Actually Monitors

Heroku ships with several built-in observability features that are genuinely useful:

Dyno metrics — CPU usage, memory consumption, and swap activity per dyno. These appear in the Heroku dashboard and via heroku ps. Heroku uses these internally to make decisions about dyno restarts when memory limits are exceeded.

Application logs — Heroku's Logplex aggregates stdout/stderr from your dynos and router logs. You can pipe these to a log drain (Papertrail, Datadog, etc.) for storage and search.

Router logs — Every HTTP request that hits your app is logged with method, path, response code, and connect/service time. These are part of the standard log stream.

Health checks — Heroku performs basic health checks during deployments to determine whether new dynos are ready to receive traffic. A release won't promote if the process can't bind to $PORT within the configured timeout.

Scheduler monitoring — If you use the Heroku Scheduler add-on, you can see when tasks last ran in the add-on dashboard.

These are all valuable. They help you understand dyno behaviour, debug slow requests, and manage deployments. What they don't do is tell you whether your application is reachable and correct from a user's perspective right now.


What Heroku Monitoring Cannot Tell You

Here is what falls completely outside Heroku's built-in observability:

Your app is returning 500s — Heroku's dyno metrics will show CPU and memory are fine. Your app process is running. But if a bad deploy pushed a database migration that broke your ORM, every request is returning a 500. Heroku has no built-in mechanism to alert you to this. The router logs will record it, but only if you've set up log draining and alerting on top — which is a separate project.

Your SSL certificate expires — Heroku manages SSL for apps using *.herokuapp.com domains, but if you've added a custom domain with your own certificate (or use Heroku's ACM on a non-Hobby+ plan), certificate expiry is your responsibility. Heroku does not alert you when your certificate is approaching expiry.

Users can't reach your app — If there's a DNS misconfiguration, a Heroku platform regional issue, or your app is erroring on boot after an automatic dyno restart at 3am, Heroku will not send you an alert. It may log a crash, but crash detection requires you to be watching the logs or have set up external alerting.

API endpoints are degraded — If your authentication endpoint is timing out because of a slow database query, your dyno metrics look normal. Response times are in the router logs, but trend analysis requires external tooling.

Your cron jobs stopped running — Heroku Scheduler fires jobs on a best-effort basis. It does not guarantee execution and does not alert you when a job fails silently or is skipped.

Geographic availability — Heroku runs your app in one of a small number of regions. A regional network issue affecting users in a specific geography might be invisible in your own testing while affecting a significant portion of your user base.


The Gap: Internal vs. External Monitoring

This is the core distinction:

Internal monitoring (what Heroku provides): observability into what your dyno is doing — CPU, memory, process state, log output.

External monitoring (what you need to add): confirmation that your service is reachable and returning correct responses from outside, the same way your users reach it.

A database connection pool exhaustion can cause every request to return 500 while your dyno memory and CPU look completely normal. A bad environment variable in a deploy can break your app completely with no dyno crash. External uptime monitoring catches these by testing the same path your users take.


What a Heroku Production App Should Monitor

The main application URL — An HTTP monitor on your primary domain, checking for a 200 response within a reasonable timeout. This is your first line of defence.

Key API endpoints — At minimum, your authentication flow and your core product functionality. A monitor on /api/health is a start, but a monitor on a representative endpoint that exercises your database and business logic is better.

Payment webhook endpoint — If you handle payments, a failing webhook receiver means failed payment processing that may not surface until customers complain. This endpoint deserves its own monitor.

SSL certificate expiry — A check that alerts you 30 days before your certificate expires, giving you time to renew without an emergency.

Scheduler heartbeats — If you have critical scheduled jobs (sending emails, processing queues, running reports), use a heartbeat monitor. Your job pings the monitor URL on success; if the ping doesn't arrive, you get alerted.


Setting Up Vigilmon for a Heroku App

Vigilmon is purpose-built for exactly this use case. Setup takes under 5 minutes:

  1. Create a monitor for your primary URL — set the expected status code to 200, set the interval to 1 minute.
  2. Add monitors for critical API endpoints and payment webhooks.
  3. Add an SSL expiry check on your custom domain.
  4. Set up a heartbeat for each scheduled job. Paste the heartbeat URL into your Scheduler task; the job hits it on success.
  5. Configure alerts to Slack, email, or webhook — wherever your team responds fastest.

Vigilmon checks from multiple geographic locations simultaneously and only fires an alert when multiple independent probes agree your app is down — which eliminates false alerts from transient network issues that don't affect real users.


What Heroku Teams Typically Discover the Hard Way

The pattern is consistent: a Heroku app runs fine for months. Then a bad deploy, a certificate expiry, or an automatic dyno restart at an off-hour leaves the app broken. The team finds out when a customer complains — not from their monitoring.

Heroku's platform handles the infrastructure. You still need to own external monitoring of the application.


Summary

Heroku is an excellent platform. Its dyno metrics, logs, and deployment health checks are genuinely useful for understanding what's happening inside your application. They are not a substitute for external uptime monitoring.

For any production Heroku application, you need an external monitor that checks whether your app is reachable and correct from your users' perspective, alerts you to SSL expiry before it becomes an incident, and confirms your scheduled jobs are actually running.

Vigilmon covers all of these, takes 5 minutes to set up, and has a free tier that handles most solo projects and early-stage products without a credit card.


Monitor your Heroku app externally at vigilmon.online — 5 monitors free, no credit card required.

Monitor your app with Vigilmon

Free plan — 5 monitors, no credit card required. Up and running in 60 seconds.

Start free →