Vercel deploys fast and scales automatically, but that doesn't make it failure-proof. An environment variable missing from your production project, an Edge Function that silently rejects requests in one geo, a Cron Job that stopped firing after a quota limit — these failures are invisible until a user complains. Vigilmon gives you the external health checks, heartbeat monitors, and status page that Vercel's own dashboard doesn't provide.
This tutorial wires a Vercel-deployed app into Vigilmon end-to-end.
What You'll Build
- An
/api/healthroute running in the Edge Runtime - Vigilmon HTTP monitors for both Edge Function and Serverless function routes
- A Vercel Cron Job that pings a Vigilmon heartbeat on each successful run
- A public status page embeddable in your app or README
Prerequisites
- A Vercel-deployed Next.js app (App Router recommended; Pages Router works too)
- Vercel Pro plan or above for Cron Jobs (Hobby plan has limited cron support)
- A free account at vigilmon.online
Step 1: Create the Edge Runtime Health Route
Edge Functions run on Vercel's global network using the V8 isolate runtime — no Node.js APIs. Your health check must use only Web-standard APIs.
App Router — app/api/health/route.ts
export const runtime = "edge";
export const dynamic = "force-dynamic";
export async function GET() {
const checks: Record<string, string> = {};
let ok = true;
// Check a downstream HTTP dependency
try {
const resp = await fetch(
process.env.DATABASE_HEALTH_URL ?? "https://example.com/ping",
{ signal: AbortSignal.timeout(3000) }
);
checks.database = resp.ok ? "ok" : `http_${resp.status}`;
if (!resp.ok) ok = false;
} catch (err) {
checks.database = `error: ${(err as Error).message}`;
ok = false;
}
// Check a second upstream (e.g. your auth service)
try {
const resp = await fetch(
process.env.AUTH_SERVICE_URL + "/health",
{ signal: AbortSignal.timeout(2000) }
);
checks.auth = resp.ok ? "ok" : `http_${resp.status}`;
if (!resp.ok) ok = false;
} catch (err) {
checks.auth = `error: ${(err as Error).message}`;
ok = false;
}
return Response.json(
{ status: ok ? "ok" : "degraded", runtime: "edge", checks },
{ status: ok ? 200 : 503 }
);
}
Pages Router — pages/api/health.ts
If you're on Pages Router and want the Edge Runtime:
import type { NextRequest } from "next/server";
export const config = { runtime: "edge" };
export default async function handler(req: NextRequest) {
const checks: Record<string, string> = {};
let ok = true;
try {
const resp = await fetch(process.env.DATABASE_HEALTH_URL!, {
signal: AbortSignal.timeout(3000),
});
checks.database = resp.ok ? "ok" : `http_${resp.status}`;
if (!resp.ok) ok = false;
} catch (err) {
checks.database = `error: ${(err as Error).message}`;
ok = false;
}
return Response.json(
{ status: ok ? "ok" : "degraded", checks },
{ status: ok ? 200 : 503 }
);
}
Deploy and verify locally:
curl https://<your-app>.vercel.app/api/health
# {"status":"ok","runtime":"edge","checks":{"database":"ok","auth":"ok"}}
Step 2: Monitor a Serverless Function Route
Not all Vercel functions run at the edge. API routes that use Node.js APIs (file system, native modules, Prisma with the default engine) run as Serverless Functions. Monitor them separately so you detect function-runtime-specific failures.
Create a Serverless Function health route alongside your Edge one:
// app/api/health-node/route.ts
// No `export const runtime = "edge"` — defaults to Node.js runtime
import { NextResponse } from "next/server";
import { db } from "@/lib/db"; // Prisma or similar
export const dynamic = "force-dynamic";
export async function GET() {
const checks: Record<string, string> = {};
let ok = true;
try {
await db.$queryRaw`SELECT 1`;
checks.database = "ok";
} catch (err) {
checks.database = `error: ${(err as Error).message}`;
ok = false;
}
return NextResponse.json(
{ status: ok ? "ok" : "degraded", runtime: "nodejs", checks },
{ status: ok ? 200 : 503 }
);
}
Step 3: Add Vigilmon HTTP Monitors
Add one Vigilmon monitor per route runtime so you get independent alerts:
Edge Function monitor
- Log in to Vigilmon → Add Monitor → HTTP.
- URL:
https://<your-app>.vercel.app/api/health - Check interval: 60 seconds
- Response timeout: 5 seconds (Edge Functions warm instantly — no cold-start budget needed)
- JSON assertion:
status=ok - Label: "Edge health — production"
Serverless Function monitor
Repeat with:
- URL:
https://<your-app>.vercel.app/api/health-node - Response timeout: 10 seconds (Serverless Functions can cold-start)
- Label: "Serverless health — production"
Step 4: Vercel Cron Job Heartbeat
Vercel Cron Jobs run your API routes on a schedule. If the cron silently stops (quota exceeded, deployment regression, runtime error), you won't know without an external heartbeat monitor.
vercel.json
{
"crons": [
{
"path": "/api/cron/daily-report",
"schedule": "0 6 * * *"
}
]
}
app/api/cron/daily-report/route.ts
export const dynamic = "force-dynamic";
export async function GET(request: Request) {
// Vercel adds this header to cron requests; check it in production
const authHeader = request.headers.get("authorization");
if (
process.env.NODE_ENV === "production" &&
authHeader !== `Bearer ${process.env.CRON_SECRET}`
) {
return new Response("Unauthorized", { status: 401 });
}
try {
await generateDailyReport(); // your actual job
// Ping Vigilmon heartbeat on success
await fetch(process.env.VIGILMON_HEARTBEAT_URL!, { method: "POST" });
return Response.json({ ok: true });
} catch (err) {
// Do NOT ping heartbeat — let Vigilmon fire the alert
console.error("Daily report failed:", err);
return Response.json({ ok: false, error: (err as Error).message }, { status: 500 });
}
}
Add to your Vercel project environment variables:
VIGILMON_HEARTBEAT_URL=https://vigilmon.online/api/heartbeat/<your-heartbeat-id>
CRON_SECRET=<random-secret>
In Vigilmon, create a Heartbeat monitor and set the grace period to 30 hours (for a daily job) so a single missed run fires an alert.
Step 5: Embed the Status Page
Vigilmon generates a public status page for all your monitors. Go to Status Pages → Create and add your Vercel monitors. Then embed the badge in your README.md:
[](https://vigilmon.online/status/<status-page-slug>)
Or embed the live widget in your app's footer:
<script
src="https://vigilmon.online/embed.js"
data-page="<status-page-slug>"
data-theme="light"
async
></script>
What You Monitor vs. What Vercel Shows You
| Failure mode | Vercel dashboard | Vigilmon | |---|---|---| | Edge Function returning 5xx | Function logs (manual check) | HTTP monitor alerts immediately | | Serverless Function cold-start timeout | Invocation duration metrics | Timeout alert fires | | Cron Job stops running | Cron log (manual check) | Heartbeat grace period fires alert | | Missing environment variable causes crash | Deploy log doesn't warn | HTTP monitor catches broken route | | Status page for your users | Not provided | Public Vigilmon status page |
Alert Channel Recommendations
- Slack webhook — post to your
#incidentschannel with the monitor name and status - Email — on-call address for P0 alerts
- PagerDuty webhook — for high-severity production monitors
Set alert escalation to re-notify every 5 minutes while the monitor is down so the alert doesn't get buried.
Vercel handles deployments. Vigilmon handles the question "is it actually working?" — from the outside, the way your users experience it.
Monitor your Vercel app with Vigilmon today — register free at vigilmon.online.