Build Instatus
KINDAback to the verdict
A status page and incident communication tool where the interesting constraints are all availability and honesty: independent infrastructure, a page that degrades to static, notifications that go out through a path unaffected by your outage, and a subscriber list that is a liability if handled carelessly.
Before step 1
Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.
- installfree
Why Runs the authoring application and the static generator.
Get it nodejs.org, or nvm install 22. open ↗
Verify
node --version prints v22 or higher - accountpennies per month for static hosting
Why This is the whole build. A status page on the same account as the product fails at exactly the moment it is needed.
Get it A second account with a different provider if possible, with its own billing so a payment problem cannot take down both.
Verify
A written list shows no shared dependency between the page and the product - have readythe price of a domain, or free for a delegated subdomain
Why Sharing a DNS provider with the product means a DNS incident removes both, and DNS incidents are a common cause of total outages.
Get it A subdomain delegated to a different provider, or a separate domain entirely.
Verify
Resolving the status hostname does not depend on the product's DNS provider - accountfree tiers cover a small subscriber list
Why Notifying subscribers through the mail infrastructure that is currently broken sends nothing.
Get it Any transactional email provider, with credentials stored somewhere retrievable during an outage.
Verify
A test notification sends and the credentials are retrievable without the product being up - decidefree
Why During an incident nobody has time to decide whether this is degraded or partial, and inconsistent statuses are what make a page untrustworthy.
Get it Write one sentence defining each status, and name who may post. Do it before the first incident, not during it.
Verify
A written definition exists for every status level and the page links to it
Data model
Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.
- components(id, name, description, ordinal, current_status) · status is operational, degraded, partial or major - incidents(id, title, impact, started_at, resolved_at, created_by) - updates(id, incident_id, status, body, at) · investigating, identified, monitoring or resolved. Append only - incident_components(incident_id, component_id, impact) - maintenance(id, title, scheduled_start, scheduled_end, body, notified_at) - subscribers(id, channel, address_hash, address_encrypted, confirmed_at, unsubscribed_at) · a list of your customers, so treated as sensitive - publishes(id, at, revision, source) · every publish of the static page, so you can prove what it said and when - Updates are append only, because editing what a status page said during an incident is how a company loses the benefit of having one.
Environment variables
These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.
| Variable | Needed | Example | Where the value comes from |
|---|---|---|---|
DATABASE_URLsecret | required | postgres://localhost:5432/status | Authoring side only. The published page does not read it, which is the point. |
PUBLISH_BUCKET | required | s3://status-example-com | Where the static page is published. On the separate account. |
PUBLISH_CREDENTIALSsecret | required | a key for the separate account | Scoped to the bucket only, and belonging to the account that shares nothing with the product. |
NOTIFY_PROVIDER_KEYsecret | optional | a provider key | The unrelated notification provider. Store it where you can reach it during an outage. |
CHECK_FAILURES_BEFORE_INCIDENT | required | 3 | Consecutive failures before automation opens an incident. One failure is noise. |
NOTIFY_RATE_LIMIT_MINUTES | required | 15 | Minimum gap between notifications for one component, so flapping does not spam. |
The build, in order
A page that is nearly impossible to take down
The status page is served as static files from infrastructure you share with nothing.
No application server in the read path. Almost nothing left to break.
Files
src/publish.tsWrite down every shared dependency and remove the ones you can.
Files
docs/independence.mdThe page must keep serving. Test it rather than assuming it.
Files
tests/independence.md
done when · tick each as it passeswatch out- Hosting the status page in the same account, region or cluster as the product means a provider incident takes out both, which is the single most common way status pages fail their one job. Separate accounts at minimum, and a different provider if you can accept the extra work.
Incidents, written once and never rewritten
An incident is posted, updated as it develops, and the history is permanent.
Enforced in the schema, not by convention.
Files
src/incidents.tsAn incident update that has not published has not happened.
Files
src/publish.tsThe history is the point. Hiding it is hiding your record.
Files
src/history.ts
done when · tick each as it passeswatch out- Editing a previous update to soften what was said, or quietly changing a start time, destroys the only thing a status page is actually for, which is being a record people can trust. Append only, with the correction visible as a correction.
Checks that can see what customers see
Automated probes run from outside and can open an incident but never close one.
A health endpoint returning true is not what customers experience.
Files
src/checks.tsOne failure is noise. Acting on it produces a page nobody trusts.
Files
src/checks.tsOnly a person closes an incident. A premature all-clear is worse than the outage.
Files
src/automation.tssrc/automation.test.ts
done when · tick each as it passeswatch out- A check running inside your own infrastructure passes happily during an outage that affects everyone outside it, which is the exact scenario you needed to detect. Probe from somewhere that shares nothing with the system, and treat a single failure as noise rather than an incident.
Telling people, through a path that still works
Subscribers hear about the incident even though your product is down.
With credentials retrievable without your product being up.
Files
src/notify.tsA subscriber list is a list of your customers. Treat it accordingly.
Files
src/subscribers.tsA flapping check must not send twenty emails. That is how people unsubscribe.
Files
src/ratelimit.ts
done when · tick each as it passeswatch out- Sending notifications through the same mail infrastructure your product uses means an outage that includes that infrastructure silences exactly the notification you needed to send. Use a separate provider, and hold the credentials somewhere that does not depend on your product being up to retrieve.
Maintenance, uptime figures and proving what you saidproduct builder
Scheduled work is announced, uptime is computed honestly, and history is provable.
With notification, since unannounced maintenance is indistinguishable from an outage.
Files
src/maintenance.tsIncluding what is excluded. An unqualified percentage is marketing.
Files
src/uptime.tsSo you can show what the page said during an incident.
Files
src/publishes.ts
done when · tick each as it passeswatch out- An uptime percentage computed by excluding maintenance windows, partial outages and anything you decided was not really an incident is marketing rather than measurement, and customers notice the discrepancy with their own experience. State the method beside the number, including what is excluded.
That is the whole plan for Instatus. What it deliberately does not cover is below · check the gaps before you call it a replacement.
- Deep integrations with monitoring platforms.
- Multi-tenant hosting for other companies.
- SMS and phone notifications.
- Private status pages with per-customer authentication.
- Deliverability someone else warms up and monitors: your first incident email is also your first send reputation test
- Notification channels beyond email: SMS, Slack app, Teams, Discord, native webhooks, RSS, all of which Instatus ships out of the box
- Per-component subscriptions, unsubscribe handling, and double opt-in that you do not have to think about
- The polish: scheduled maintenance windows, incident templates, timezone handling, embeddable widgets, public API
- Real independence, unless you actually do the work to host the page away from your own stack
- A machine-readable status endpoint, which is what other people's tooling wants
- Incident templates, since nobody writes well at three in the morning
- Post-incident notes attached to the incident, which is where a status page earns trust
Need the files? The project pack on the verdict page hands your agent the whole brief · more uptime.