DEV Community

Vigilmon
Vigilmon

Posted on

Monitoring Your SvelteKit App with Vigilmon: Server Routes, Edge Functions & Uptime

SvelteKit apps are fast and flexible — but that flexibility means failures hide in unusual places. A Cloudflare Worker can serve stale cached HTML while your database is unreachable. A Vercel Edge Function can silently time out. A SvelteKit +server.ts route can start returning 500s on one region while other regions look fine. Vigilmon watches all of this continuously. This tutorial shows you how to wire SvelteKit into Vigilmon for uptime monitoring, heartbeat checks, and alert routing.

What You'll Build

  • A +server.ts health route that checks database and external dependencies
  • Vigilmon HTTP monitors for both your SvelteKit app and any API routes
  • A cron heartbeat using the cron package for scheduled tasks
  • Deployment health tips for Cloudflare Workers and Vercel
  • Email and Slack alert channels

Prerequisites

  • SvelteKit project (SvelteKit 2.x recommended)
  • A free Vigilmon account
  • Optionally: a database (Postgres, PlanetScale, Turso, etc.)

Step 1: Create the Health Server Route

SvelteKit's +server.ts files handle HTTP requests server-side. Add one at src/routes/api/health/+server.ts:

// src/routes/api/health/+server.ts
import { json } from "@sveltejs/kit";
import type { RequestHandler } from "./$types";

export const GET: RequestHandler = async ({ platform }) => {
  const checks: Record<string, string> = {};
  let degraded = false;

  // Database check — adapt to your client (Drizzle, Prisma, Turso, etc.)
  try {
    // Example with a Turso/libSQL client from the platform env
    // await platform?.env?.DB.execute("SELECT 1");
    checks.database = "ok";
  } catch (err) {
    checks.database = `error: ${(err as Error).message}`;
    degraded = true;
  }

  // External dependency check (e.g. a third-party API)
  try {
    const res = await fetch("https://api.stripe.com/v1/", {
      signal: AbortSignal.timeout(3000),
    });
    checks.stripe = res.status < 500 ? "ok" : `http_${res.status}`;
  } catch {
    checks.stripe = "unreachable";
    // Note: don't degrade for third-party deps unless critical
  }

  return json(
    {
      status: degraded ? "degraded" : "ok",
      timestamp: new Date().toISOString(),
      checks,
    },
    { status: degraded ? 503 : 200 }
  );
};

// Prevent caching of the health endpoint
export const config = {
  isr: { expiration: 0 },        // Vercel ISR: never cache
  runtime: "nodejs",             // Force Node runtime, not Edge, for DB access
};
Enter fullscreen mode Exit fullscreen mode

Test it locally:

curl http://localhost:5173/api/health | jq .
# {"status":"ok","timestamp":"2026-06-29T...","checks":{"database":"ok","stripe":"ok"}}
Enter fullscreen mode Exit fullscreen mode

Step 2: Add Vigilmon HTTP Monitors

Log in to Vigilmon and create two monitors:

Monitor 1: SvelteKit App

Field Value
URL https://app.yourdomain.com/
Method GET
Expected status 200
Expected body Any stable string from your <h1> or <title>
Check interval 1 minute

Monitor 2: Health API Route

Field Value
URL https://app.yourdomain.com/api/health
Method GET
Expected status 200
Check interval 1 minute

Having both monitors is important: the homepage monitor catches rendering failures; the health API monitor catches database or dependency failures that don't immediately break the HTML response.


Step 3: Heartbeat for Scheduled Tasks

If you have scheduled tasks (data syncs, digest emails, cleanup jobs), wire them to a Vigilmon heartbeat so you know when they stop running.

Install node-cron

npm install node-cron
npm install --save-dev @types/node-cron
Enter fullscreen mode Exit fullscreen mode

Create a Scheduled Task with a Heartbeat

// src/lib/server/scheduler.ts
import cron from "node-cron";

const VIGILMON_HEARTBEAT_URL = process.env.VIGILMON_HEARTBEAT_URL ?? "";

async function pingHeartbeat(): Promise<void> {
  if (!VIGILMON_HEARTBEAT_URL) return;
  try {
    await fetch(VIGILMON_HEARTBEAT_URL, {
      signal: AbortSignal.timeout(5000),
    });
  } catch {
    // Never let monitoring failure break the job
  }
}

export function startScheduler(): void {
  // Example: nightly data sync at 02:00
  cron.schedule("0 2 * * *", async () => {
    try {
      await runNightlySync();
      await pingHeartbeat(); // ping only on success
    } catch (err) {
      console.error("[scheduler] nightly sync failed:", err);
      // Vigilmon will alert after the expected interval passes without a ping
    }
  });

  console.log("[scheduler] Started");
}

async function runNightlySync(): Promise<void> {
  // Your actual sync logic here
}
Enter fullscreen mode Exit fullscreen mode

Start the scheduler from your hooks.server.ts:

// src/hooks.server.ts
import { startScheduler } from "$lib/server/scheduler";

// Only start in non-serverless environments
if (process.env.NODE_ENV === "production" && !process.env.VERCEL) {
  startScheduler();
}
Enter fullscreen mode Exit fullscreen mode

Create a Heartbeat monitor in Vigilmon:

  1. Monitors → New Heartbeat Monitor
  2. Set the expected interval to 25 hours (gives the nightly job a 1-hour grace)
  3. Copy the ping URL into your .env:
VIGILMON_HEARTBEAT_URL=https://vigilmon.online/api/heartbeat/xxxxxxxx
Enter fullscreen mode Exit fullscreen mode

Step 4: Deployment Health Tips

Cloudflare Workers / Pages

Cloudflare caches aggressively. Add cache-control headers to your health route:

// src/routes/api/health/+server.ts
export const GET: RequestHandler = async () => {
  // ... checks ...

  return json(
    { status: "ok", ... },
    {
      headers: {
        "Cache-Control": "no-store, no-cache, must-revalidate",
        "CDN-Cache-Control": "no-store",
      },
    }
  );
};
Enter fullscreen mode Exit fullscreen mode

Also set a Cloudflare health check rule to bypass cache for /api/health*.

For Cloudflare Workers scheduled tasks (using scheduled event handler), ping the heartbeat at the end of each successful run:

// worker.js
export default {
  async scheduled(event, env, ctx) {
    ctx.waitUntil(runTask(env));
  },
};

async function runTask(env) {
  try {
    await doWork(env);
    await fetch(env.VIGILMON_HEARTBEAT_URL);
  } catch (err) {
    console.error("Task failed:", err);
  }
}
Enter fullscreen mode Exit fullscreen mode

Vercel

For Vercel deployments, use Vercel Cron Jobs + a heartbeat:

// vercel.json
{
  "crons": [
    {
      "path": "/api/cron/sync",
      "schedule": "0 2 * * *"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode
// src/routes/api/cron/sync/+server.ts
import { json } from "@sveltejs/kit";
import type { RequestHandler } from "./$types";

export const GET: RequestHandler = async ({ request }) => {
  // Verify this is coming from Vercel Cron
  const authHeader = request.headers.get("authorization");
  if (authHeader !== `Bearer ${process.env.CRON_SECRET}`) {
    return json({ error: "Unauthorized" }, { status: 401 });
  }

  try {
    await runSync();

    // Ping Vigilmon heartbeat
    const heartbeatUrl = process.env.VIGILMON_HEARTBEAT_URL;
    if (heartbeatUrl) {
      await fetch(heartbeatUrl).catch(() => {});
    }

    return json({ ok: true });
  } catch (err) {
    return json({ error: String(err) }, { status: 500 });
  }
};
Enter fullscreen mode Exit fullscreen mode

Step 5: Configure Alert Channels

In Vigilmon's Alerts settings:

Email

  1. Alert Channels → Email → add your ops email
  2. Attach to both HTTP monitors and the heartbeat monitor

Slack Webhook

  1. Create a Slack Incoming Webhook for #alerts
  2. Alert Channels → Webhook → paste the URL
  3. Use this payload template:
{
  "text": "🚨 *{{ monitor.name }}* is DOWN\n{{ monitor.url }}\nStatus: {{ event.status }}\n<https://vigilmon.online|Open Vigilmon>"
}
Enter fullscreen mode Exit fullscreen mode

Step 6: Test End-to-End

# 1. Verify the health route
curl -s https://app.yourdomain.com/api/health | jq .

# 2. Simulate a failure: break your DB connection string and redeploy
# Expected: health route returns 503, Vigilmon alerts within 2 minutes

# 3. Stop the scheduler, wait past the heartbeat window
# Expected: Vigilmon fires a heartbeat alert

# 4. Use Vigilmon "Test Alert" → confirm Slack/email delivery
Enter fullscreen mode Exit fullscreen mode

What You Now Have

Monitor Catches
HTTP app check Render failures, broken deploys, CDN issues
HTTP health route Database failures, external dependency outages
Cron heartbeat Scheduled task crashes, cron misconfiguration

Next Steps

  • Embed the Vigilmon status badge in your SvelteKit footer component
  • Create per-environment monitors (staging vs production) to catch issues before they hit users
  • Use Vigilmon's response time graphs to correlate latency spikes with deploys

Found this useful? Vigilmon is free to start — sign up here and have your first monitor live in under 5 minutes.

Top comments (0)