Encore.ts is a TypeScript backend framework with a distinctive premise: you declare your infrastructure (APIs, databases, queues, secrets) as code, and Encore provisions it — whether locally in the dev environment or deployed to Encore Cloud. The framework generates your API surface from TypeScript function signatures, which means you get automatic client libraries and type-safe interfaces for free.
When Encore.ts applications run in production — whether on Encore Cloud or self-hosted — they still need external uptime monitoring. Encore's own dashboards tell you about deployment health; Vigilmon tells you what external users experience.
Prerequisites
- Node.js 18+ with
encoreCLI installed (npm install -g encore.dev) - An Encore.ts backend project
- A free account at vigilmon.online
Part 1: Add a health service
In Encore.ts, every API group is a service. Create a dedicated health service:
// health/health.ts
import { api } from 'encore.dev/api';
interface HealthCheck {
name: string;
status: 'ok' | 'error';
message?: string;
}
interface HealthResponse {
status: 'ok' | 'degraded';
timestamp: string;
service: string;
checks: HealthCheck[];
}
// Encore declares this as an unauthenticated GET endpoint
export const check = api(
{ expose: true, method: 'GET', path: '/health', auth: false },
async (): Promise<HealthResponse> => {
const checks: HealthCheck[] = [];
let degraded = false;
// Check a database connection (Encore injects DB clients automatically)
try {
// Replace with your actual Encore database import and query
// const row = await db.queryRow`SELECT 1 as ok`;
checks.push({ name: 'database', status: 'ok' });
} catch (err) {
checks.push({ name: 'database', status: 'error', message: String(err) });
degraded = true;
}
return {
status: degraded ? 'degraded' : 'ok',
timestamp: new Date().toISOString(),
service: 'health',
checks,
};
}
);
Encore auto-generates the REST endpoint at GET /health. The auth: false setting ensures Vigilmon can reach it without an authentication token.
Test locally:
encore run
curl http://localhost:4000/health
{
"status": "ok",
"timestamp": "2026-06-30T10:00:00.000Z",
"service": "health",
"checks": [
{ "name": "database", "status": "ok" }
]
}
When any check fails, status becomes "degraded". Encore.ts does not natively set HTTP 503 for application-level errors via the standard api() helper — if you need a 503, throw an APIError:
import { APIError, ErrCode } from 'encore.dev/api';
// At the end of your handler:
if (degraded) {
throw APIError.internal('Health check failed: one or more dependencies are degraded');
}
With the APIError approach, Vigilmon catches the 5xx HTTP status directly. Without it, rely on keyword assertion (Part 2 below) to detect "degraded" in the response body.
Part 2: Set up HTTP monitoring in Vigilmon
- Log in to vigilmon.online and click Add Monitor.
- Choose HTTP(S) monitor.
For Encore Cloud deployments:
- URL:
https://yourapp-production.encr.app/health(find the URL in your Encore Cloud dashboard)
For self-hosted Encore deployments:
- URL:
https://yourapp.example.com/health
- Interval: 1 minute.
- Under Keyword assertion, enter
"status":"ok"— Vigilmon fails the check if this string is absent from the response body, catching the degraded state even when HTTP 200 is returned. - Add your alert channel (email, Slack, or webhook URL).
- Click Save.
Vigilmon probes from multiple geographic regions, requiring a quorum of failures before firing an alert. This eliminates false positives from regional routing issues.
Part 3: Webhook alerting
Add a webhook endpoint to your Encore backend to receive DOWN/UP events from Vigilmon:
// health/webhook.ts
import { api, APIError, ErrCode } from 'encore.dev/api';
interface VigilmonPayload {
monitor_name: string;
status: 'down' | 'up';
url: string;
response_code: number;
checked_at: string;
}
export const vigilmonWebhook = api(
{ expose: true, method: 'POST', path: '/webhook/vigilmon', auth: false },
async (payload: VigilmonPayload): Promise<{ received: boolean }> => {
if (payload.status === 'down') {
console.error('[VIGILMON] Monitor DOWN', {
monitor: payload.monitor_name,
url: payload.url,
code: payload.response_code,
at: payload.checked_at,
});
// Notify via Slack, PagerDuty, etc.
const slackUrl = process.env['SLACK_WEBHOOK_URL'];
if (slackUrl) {
await fetch(slackUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
text: `*DOWN*: ${payload.monitor_name} — ${payload.url}`,
}),
});
}
} else {
console.info('[VIGILMON] Recovered', payload.monitor_name);
}
return { received: true };
}
);
In Vigilmon, add a Webhook alert channel pointing at https://yourapp.example.com/webhook/vigilmon.
Part 4: Heartbeat monitoring for Encore cron jobs
Encore.ts has a built-in cron job system. Use a Vigilmon heartbeat monitor to detect when a cron task silently stops executing.
Define a cron job in Encore:
// jobs/cleanup.ts
import { CronJob } from 'encore.dev/cron';
import { api } from 'encore.dev/api';
// Internal endpoint the cron job calls
export const runCleanup = api(
{ expose: false },
async (): Promise<{ cleaned: number }> => {
const count = await performCleanup();
// Ping Vigilmon heartbeat on success
await pingHeartbeat();
return { cleaned: count };
}
);
// Encore CronJob — fires every hour
const _ = new CronJob('hourly-cleanup', {
title: 'Hourly data cleanup',
every: '1h',
endpoint: runCleanup,
});
async function performCleanup(): Promise<number> {
// Your cleanup logic
return 0;
}
async function pingHeartbeat(): Promise<void> {
const url = process.env['VIGILMON_HEARTBEAT_URL'];
if (!url) return;
try {
await fetch(url, { signal: AbortSignal.timeout(5_000) });
} catch (err) {
console.warn('Heartbeat ping failed:', err);
}
}
In Vigilmon, create a Heartbeat monitor with an expected interval of 65 minutes (5 minutes longer than the cron schedule — accounts for execution time variance). If the cron job stops firing, the heartbeat lapses and Vigilmon alerts.
Encore Cloud vs self-hosted
| Concern | Encore Cloud | Self-hosted |
|---|---|---|
| Health endpoint URL | https://yourapp-production.encr.app/health | https://yourapp.example.com/health |
| Deployment observability | Built into Encore Cloud dashboard | Your own logging/APM |
| Vigilmon monitoring | External, user-perspective uptime | Same — Vigilmon is always external |
| Secrets / env vars | Managed via encore secret set | Your own secret manager |
Encore Cloud's built-in observability covers deployment metrics and traces. Vigilmon covers the question Encore Cloud cannot answer: "Is my endpoint reachable from the public internet right now, from multiple locations?"
Summary
| What to monitor | How |
|---|---|
| API health endpoint | HTTP monitor on /health |
| Application-level errors | Keyword assertion: "status":"ok" |
| Cron job execution | Heartbeat monitor + pingHeartbeat() |
| Team alerts | Webhook → Slack |
Encore.ts removes infrastructure boilerplate; Vigilmon removes the monitoring blind spot. Together, they let a small team ship a production TypeScript backend with confidence.