Introduction
A themeable, TypeScript-first status page for React Router, Next.js and Astro.
Heyo Status is a status page you own. It monitors services on a schedule, stores uptime history, publishes incident timelines and maintenance windows, notifies your team and your subscribers, and renders a server-side status page in React Router, Next.js or Astro. One configuration file describes all of it; the CLI, the HTTP API, the scheduler and the UI read the same object.
Loading repository data…
What it does
| Capability | Summary |
|---|---|
| Monitoring | Scheduled http, ssl, tcp, dns and composite checks with timeouts and assertions. |
| History | Raw results compacted into daily summaries, with configurable retention and display windows. |
| Incidents | Manual or automatically opened incidents with a status timeline and severity. |
| Maintenance | Scheduled windows that suppress alerts and publish on the page. |
| Notifications | Slack, Discord, signed webhooks and email (Resend, SES, Cloudflare, SMTP), with a delivery log. |
| Subscriptions | Opt-in public subscriptions over email, RSS/Atom and webhooks, with double opt-in. |
| Observability | SVG badges, a Prometheus exposition, RSS and Atom feeds and a health endpoint. |
| UI | Five bundled themes, one stylesheet, SSR-first markup that works without JavaScript. |
The shape of a project
Three files make a status page. A configuration, a catch-all API route, and a page that renders a snapshot:
Everything else — the CLI, the scheduler, badges, feeds, notifications — is
derived from the same statusPage object.
Design decisions worth knowing up front
heyo-status.config.ts lives in the project root. The CLI loads it from
there, the generated routes import it, and the deployment overlays expect it.
Moving it means passing --config to every CLI command.
- The runtime is framework-neutral. The HTTP surface is a single
Hono app behind
statusPage.handler(request). The framework adapters are thin: they hand aRequestover and return aResponse. - Persistence is an interface. Core code only ever talks to
StatusDatabaseAdapter. SQLite, D1 and PostgreSQL are implementations of it, and so is anything you write yourself. - Writes are closed by default.
/admin/*refuses every request until an admin token is configured. Public subscriptions are disabled by default, and visitor-supplied webhooks need an extra opt-in. - The page renders on the server. Incident disclosures and monitor groups
are native
<details>elements, because a status page has to stay readable exactly when the JavaScript bundle does not load.
Runtime requirements
| Runtime | Requirement |
|---|---|
CLI and dev scripts | Bun 1.4.3+, even when installing with pnpm, npm or Yarn. |
| Next.js, React Router | Node.js 20.19+ in production for native TCP/TLS checks. |
| Astro 7 | Node.js 22.12+. |
| Cloudflare Workers | No node:net/node:tls, so tcp and ssl monitors report unavailable. |