A deploy that succeeds tells you the build compiled and the process started. It does not tell you the site loads, the database is reachable, or that the checkout flow still works. Those are separate facts, and by default nobody is checking any of them.
The usual way a solo developer learns their site is down is an email from the one user who cared enough to write.
The idea
Monitoring means something outside your app asks it a question on a schedule, and shouts at a human when the answer changes. Two kinds cover almost everything a small project needs: an uptime check that asks "are you alive?" from the outside, and an error tracker that reports exceptions from the inside. Both have free tiers that fit a project with no revenue.
OUTSIDE YOUR APP INSIDE
------- -------- ------
UptimeRobot --- GET /api/health ---> 200 OK
| | db.query('select 1')
| 2 failures in a row | storage ping
v |
email + SMS to you exception thrown
|
v
Sentry ---> alert: 41 users hit thisHow it works
A Health check endpointA URL your app exposes whose only job is to answer "am I working?" It checks its own dependencies and returns a success or failure code.
is a route like /api/health that does slightly more than return "ok". A useful one runs a trivial
query against the database and touches whatever else the app cannot live without, then returns
HTTP 200 if everything answered and 500 if anything did not. Ten lines of code. Ask Claude Code for
it by name.
An uptime service (UptimeRobot, Better Stack, Cronitor, or Cloudflare's own health checks) requests that URL every one to five minutes from somewhere that is not your machine. When it gets a failure or a timeout, it emails or texts you. Configure it to alert on the second consecutive failure, so one blip at 4am does not wake you.
An error tracker (Sentry is the common one; Bugsnag and Rollbar are the same category) is a small library you install into the app itself. When an exception is thrown in production it sends the stack trace, the URL, the browser, and a count of how many people hit it. That last number is the one you cannot get any other way. It is the difference between a typo one person found and a bug affecting everyone since Tuesday.
What to do
- Add
/api/healthand make it actually query the database. A health check that returns a hardcoded{ok: true}will happily report success while your data layer is on fire. - Point a free UptimeRobot monitor at it, set the interval to five minutes, and add your phone number. This takes about ten minutes and is the single highest-value thing in this chapter.
- Install Sentry in the app and deliberately throw one error in production to confirm the alert actually reaches your inbox. Plenty of them silently do not, usually because of a spam filter or a notification setting nobody looked at.
Where it breaks
Uptime checks only prove the URL they request. A monitor pointed at your homepage will stay green while signup, payments and email are all broken, because none of those is on the homepage. This is a real trap: it looks like coverage and is not. Point checks at the paths that touch your dependencies.
Alerts also decay. Once you have three flapping monitors that cry wolf every week you will start ignoring the emails, and then you have monitoring with none of the benefit. Fewer checks that you trust beat a dashboard you have learned to dismiss. Delete a noisy monitor rather than muting it.
Finally, error trackers see your users' data. Sentry can capture request bodies and cookies, which means passwords and tokens can end up in a third party's dashboard if you turn on everything. Leave the defaults, and scrub the fields you know are sensitive.