How to Monitor Your Deno App with Vigilmon
Deno is a secure, modern JavaScript and TypeScript runtime that's gaining traction for its built-in permissions model and first-class TypeScript support. But fast runtime ≠ always-up service. Production Deno apps need uptime monitoring just like any other backend.
In this tutorial you'll add a /health endpoint to a Deno HTTP server, wire it up to Vigilmon, and configure alerts so you know within minutes when something breaks.
What You'll Build
- A minimal Deno HTTP server with a structured health-check endpoint
- A Vigilmon monitor that polls the endpoint every 5 minutes from multiple regions
- Email (and optionally webhook) alerts when the app goes down
Prerequisites
Step 1: Create a Deno HTTP Server with a Health Endpoint
Start with a basic Deno server that handles real routes and exposes a /health path:
// main.ts
const PORT = parseInt(Deno.env.get("PORT") ?? "8000");
async function handler(req: Request): Promise<Response> {
const url = new URL(req.url);
if (url.pathname === "/health") {
const body = JSON.stringify({
status: "ok",
timestamp: new Date().toISOString(),
version: "1.0.0",
});
return new Response(body, {
status: 200,
headers: { "Content-Type": "application/json" },
});
}
if (url.pathname === "/") {
return new Response("Hello from Deno!", { status: 200 });
}
return new Response("Not Found", { status: 404 });
}
console.log(`Server running on http://localhost:${PORT}`);
Deno.serve({ port: PORT }, handler);
Run it:
deno run --allow-net --allow-env main.ts
Test the health endpoint:
curl http://localhost:8000/health
# {"status":"ok","timestamp":"2024-01-15T10:30:00.000Z","version":"1.0.0"}
The endpoint returns HTTP 200 with a JSON body — exactly what Vigilmon expects.
Step 2: Add a Deep Health Check
A shallow "always returns 200" endpoint misses real failures like a broken database connection. Add a deeper check that tests actual dependencies:
// health.ts
interface HealthStatus {
status: "ok" | "degraded" | "down";
checks: Record<string, boolean>;
timestamp: string;
}
export async function buildHealthResponse(): Promise<[HealthStatus, number]> {
const checks: Record<string, boolean> = {};
// Example: check that a critical file/config is readable
try {
await Deno.stat("./config.json");
checks.config = true;
} catch {
checks.config = false;
}
// Example: check an external dependency (replace with your DB/cache ping)
try {
const res = await fetch("https://httpbin.org/status/200", {
signal: AbortSignal.timeout(3000),
});
checks.externalApi = res.ok;
} catch {
checks.externalApi = false;
}
const allOk = Object.values(checks).every(Boolean);
const status: HealthStatus = {
status: allOk ? "ok" : "degraded",
checks,
timestamp: new Date().toISOString(),
};
return [status, allOk ? 200 : 503];
}
Update main.ts to use it:
import { buildHealthResponse } from "./health.ts";
// Inside handler:
if (url.pathname === "/health") {
const [status, httpCode] = await buildHealthResponse();
return new Response(JSON.stringify(status), {
status: httpCode,
headers: { "Content-Type": "application/json" },
});
}
Now the endpoint returns 503 when a dependency fails — Vigilmon treats non-2xx as a downtime event and fires an alert.
Step 3: Deploy Your Deno App
Before Vigilmon can monitor your app it needs to be publicly reachable. Common Deno hosting options:
Deno Deploy (official, free tier):
# Install deployctl
deno install --allow-read --allow-write --allow-env --allow-net --allow-run --no-check -r -f https://deno.land/x/deploy/deployctl.ts
# Deploy
deployctl deploy --project=my-deno-app main.ts
Your app gets a URL like https://my-deno-app.deno.dev.
Docker / VPS (if you self-host):
FROM denoland/deno:1.40.0
WORKDIR /app
COPY . .
RUN deno cache main.ts
CMD ["run", "--allow-net", "--allow-env", "main.ts"]
Note your public URL — you'll need it in the next step.
Step 4: Create a Vigilmon Monitor
- Log in at vigilmon.online and click + New Monitor.
- Set Monitor Type to HTTP / HTTPS.
- Paste your health endpoint URL, e.g.
https://my-deno-app.deno.dev/health. - Set Check Interval to 5 minutes (the free-tier minimum).
- Under Expected Status, leave it at 2xx (or enter
200specifically). - Click Save Monitor.
Vigilmon immediately begins polling from multiple geographic regions. If the majority of region checks fail it counts as a real outage — not a false alarm from a single-location blip.
Step 5: Configure Alert Channels
Email Alerts
Go to Settings → Alert Channels → Add Channel → Email, enter your address, and save. Assign the channel to your new monitor under Monitors → Edit → Alert Channels.
Webhook Alerts (Slack, PagerDuty, custom)
- Settings → Alert Channels → Add Channel → Webhook.
- Paste your Slack incoming-webhook URL (or any HTTPS endpoint).
- Vigilmon sends a JSON POST on every state change (up → down, down → up).
Example payload your endpoint receives:
{
"monitor": "my-deno-app /health",
"status": "down",
"reason": "HTTP 503",
"checked_at": "2024-01-15T10:31:00Z",
"regions": ["us-east", "eu-west", "ap-south"]
}
Step 6: Test the Alert Pipeline
Simulate a failure by returning 503 from your health endpoint:
// Temporarily force a failure to test alerting
if (url.pathname === "/health") {
return new Response(JSON.stringify({ status: "down" }), { status: 503 });
}
Redeploy, wait up to 5 minutes for the next check cycle, and you should receive an alert. Then revert and confirm you get the recovery notification.
Step 7: Add a Status Badge (Optional)
Vigilmon provides an embeddable badge you can add to your README or status page:

Find your monitor ID in the Vigilmon dashboard URL (/monitors/123) and replace <your-monitor-id>.
Deno-Specific Tips
Permission scoping: Lock down your Deno permissions in production. If your app only needs network access, use --allow-net=0.0.0.0:8000 instead of --allow-net.
Deno Deploy edge functions: If you deploy to Deno Deploy's edge, add a separate monitor for each custom domain or region-specific URL you expose.
Graceful shutdown: Deno's Deno.addSignalListener("SIGTERM", ...) lets you drain connections cleanly before the process exits — Vigilmon will mark the app as down only after the check fails, not on the first missed ping.
Wrapping Up
In about 10 minutes you've gone from a bare Deno server to a production-monitored application:
- Health endpoint returning structured JSON with real dependency checks
- Vigilmon polling every 5 minutes from multiple regions
- Immediate alerts via email or Webhook when the app goes down
The free tier at vigilmon.online supports up to 5 monitors with no credit card required — plenty to cover a side project or early-stage product.
Have questions or found a better pattern for Deno health checks? Drop a comment below.
Top comments (0)