tutorial

Elysia Application Monitoring with Vigilmon: Health Checks and Uptime Alerts

Add production-grade uptime monitoring to your Elysia (Bun) application — health endpoints, HTTP monitors, keyword checks, and alert routing with Vigilmon.

Elysia is the fastest HTTP framework for Bun, built for high-throughput APIs and type-safe end-to-end development. Its performance profile makes it tempting to skip observability tooling — "it's fast, surely nothing breaks." But outages don't care how fast your framework is. A database connection pool exhausted at midnight, a failed deployment that returns 500s on one route, an SSL certificate that expired while you were heads-down shipping — these failures need an independent observer.

Vigilmon polls your app's health endpoint every minute from external locations and alerts you the moment it breaks. This tutorial walks you through wiring Elysia into Vigilmon in under 15 minutes.

What You'll Build

  • A /health endpoint in Elysia that reflects real dependency state
  • A Vigilmon HTTP monitor with multi-region polling
  • A keyword monitor for your HTML frontend (if applicable)
  • Email and Slack webhook alert channels

Prerequisites

  • Bun v1.0+ installed
  • An Elysia project (bun create elysia my-app or existing)
  • A free Vigilmon account (5 monitors free, no credit card)

Step 1: Add a Health Endpoint

Elysia's decorator system makes adding a health route clean and type-safe. Add it early in your route definitions so it's never shadowed by a wildcard handler.

// src/index.ts
import { Elysia } from 'elysia'

const app = new Elysia()

app.get('/health', async () => {
  const checks: Record<string, string> = {}
  let ok = true

  // Database ping — adapt this to your actual DB client
  try {
    const start = performance.now()
    // await db.execute('SELECT 1')  ← your DB query here
    checks.database = `ok (${Math.round(performance.now() - start)}ms)`
  } catch (err) {
    checks.database = `error: ${(err as Error).message}`
    ok = false
  }

  // External dependency probe
  try {
    const res = await fetch('https://api.yourupstream.com/ping', {
      signal: AbortSignal.timeout(3000),
    })
    checks.upstream = res.ok ? 'ok' : `http_${res.status}`
    if (!res.ok) ok = false
  } catch (err) {
    checks.upstream = `error: ${(err as Error).message}`
    ok = false
  }

  return new Response(
    JSON.stringify({
      status: ok ? 'ok' : 'degraded',
      checks,
      timestamp: new Date().toISOString(),
    }),
    {
      status: ok ? 200 : 503,
      headers: { 'Content-Type': 'application/json' },
    }
  )
})

app.get('/', () => 'Hello from Elysia!')

app.listen(3000)
console.log(`Server running at http://localhost:${app.server?.port}`)

Start the server and test it:

bun run src/index.ts
curl -s http://localhost:3000/health | bun -e "const t = await Bun.stdin.text(); console.log(JSON.stringify(JSON.parse(t), null, 2))"

Expected output when healthy:

{
  "status": "ok",
  "checks": {
    "database": "ok (1ms)",
    "upstream": "ok"
  },
  "timestamp": "2025-06-30T10:00:00.000Z"
}

When a dependency fails, status becomes "degraded" and the HTTP response code is 503. Vigilmon treats any non-2xx status as a downtime event and triggers the alert chain immediately.


Step 2: Use Elysia's Lifecycle Hooks for Accurate Timing

Elysia's onRequest / onResponse lifecycle hooks let you measure real handler latency and expose it in the health payload — useful for detecting performance regressions before they become outages.

import { Elysia } from 'elysia'

let lastRequestMs: number | null = null

const app = new Elysia()
  .onRequest(() => {
    lastRequestMs = performance.now()
  })
  .get('/health', () => {
    return {
      status: 'ok',
      lastHandlerMs: lastRequestMs
        ? Math.round(performance.now() - lastRequestMs)
        : null,
      timestamp: new Date().toISOString(),
    }
  })

This is optional but surfacing lastHandlerMs in your health payload lets you set a Vigilmon response time alert — get notified if your API slows past an SLA threshold even while technically returning 200.


Step 3: Deploy Your Elysia App

Your app needs a public URL before Vigilmon can poll it.

Fly.io works great with Bun:

# fly.toml
app = "my-elysia-app"
primary_region = "iad"

[http_service]
  internal_port = 3000
  force_https = true

[[vm]]
  memory = "256mb"
  cpu_kind = "shared"
  cpus = 1
fly launch --no-deploy
fly deploy

Railway and Render also support Bun out of the box — set the start command to bun run src/index.ts and they handle the rest.

Note your production health URL: https://my-elysia-app.fly.dev/health


Step 4: Create a Vigilmon HTTP Monitor

  1. Log in at vigilmon.online and click Add Monitor → HTTP.
  2. Fill in the monitor settings:

| Field | Value | |---|---| | URL | https://my-elysia-app.fly.dev/health | | Method | GET | | Check interval | 60 seconds | | Expected status | 200 | | Timeout | 10 seconds | | Regions | Select 2–3 for triangulation |

  1. Under Advanced, enable a JSON body assertion:

    • Path: status
    • Expected value: ok
  2. Click Save.

Vigilmon begins polling immediately. Within 90 seconds you'll see the first green tick on your dashboard. The JSON body assertion means Vigilmon alerts you even if your endpoint returns 200 with "status": "degraded" — which happens when a dependency is broken but your server is still running.


Step 5: Add a Keyword Monitor for Your Frontend

If your Elysia app serves HTML pages (using Elysia's html plugin), add a second monitor:

  1. Add Monitor → HTTP
  2. URL: https://my-elysia-app.fly.dev/
  3. Expected status: 200
  4. Keyword check: must contain a string unique to your app (e.g., your app name or a copyright string)

This catches the scenario where a CDN or proxy serves a cached error page with a 200 status — a plain HTTP status check would miss it entirely.


Step 6: Configure Alert Channels

Go to Alert Channels → Add channel.

Email

Add your on-call email address. Vigilmon sends alerts on:

  • Non-2xx HTTP status from any polled region
  • JSON body assertion failure
  • Response timeout exceeded

Slack Webhook

  1. Create a Slack Incoming Webhook in your workspace.
  2. In Vigilmon: Alert Channels → Add → Webhook, paste the URL, save.
  3. Assign the webhook channel to your monitors.

When the monitor fires you'll see:

🔴 my-elysia-app /health is DOWN
Status: 503 | Checked at: 2025-06-30 10:31 UTC

And when it recovers:

🟢 my-elysia-app /health is back UP (was down 3m 12s)


Step 7: Test the Alert Pipeline

Force a failure to verify alerts flow end-to-end before you need them at 2 AM:

// Temporarily override the health route
app.get('/health', () =>
  new Response(JSON.stringify({ status: 'degraded', checks: { database: 'simulated error' } }), {
    status: 503,
    headers: { 'Content-Type': 'application/json' },
  })
)

Deploy, wait one check interval (≤ 60s), and confirm the Slack/email notification arrives. Revert and confirm the recovery alert.


Production Checklist

  • [ ] /health checks all real dependencies (DB, cache, upstream APIs)
  • [ ] Unhealthy checks return 503, not 200
  • [ ] JSON body assertion enabled in Vigilmon
  • [ ] Alert channels tested end-to-end before your first production incident
  • [ ] Maintenance window configured for deployments to mute false alerts

Wrapping Up

Elysia's speed means you'll ship fast — monitoring with Vigilmon means you'll catch the breakages just as fast. You now have:

  • A health endpoint that reflects real app state
  • Vigilmon polling every 60 seconds from multiple regions
  • Slack and email alerts the moment something breaks

Sign up for Vigilmon free — no credit card required, first 5 monitors included.

Building something with Elysia? Drop your stack in the comments.

Monitor your app with Vigilmon

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

Start free →