Nitric is a cloud portability framework for building backend applications. You define APIs, queues, buckets, secrets, and scheduled tasks using Nitric's cloud-agnostic SDK; Nitric compiles those definitions into the appropriate cloud resources on AWS, GCP, or Azure without requiring you to write cloud-specific infrastructure code. The framework abstracts away the provider — but once your application is deployed, the services you expose are real cloud endpoints, and they need real external monitoring. Vigilmon provides that. It sits entirely outside your cloud infrastructure and probes your Nitric services from multiple geographic regions, alerting you when an endpoint becomes unavailable regardless of which cloud provider is running it.
This tutorial covers adding external uptime monitoring to Nitric TypeScript applications deployed to any cloud.
What You'll Build
- A
/healthroute in a Nitric API that validates runtime dependencies - A Vigilmon HTTP monitor with keyword assertions
- A heartbeat monitor for Nitric scheduled tasks
- Alert channels that notify your team when services go down
Prerequisites
- Node.js 18+ with the
nitricCLI installed (npm install -g @nitric/cli) - A Nitric TypeScript application
- A free account at vigilmon.online
Step 1: Add a Health Route to Your Nitric API
Nitric APIs are defined using the api() helper. Add a /health route to an existing API or create a dedicated one. The health check should validate actual runtime dependencies — not a static response that passes even when the underlying resources are unhealthy.
// services/health.ts
import { api, kv } from '@nitric/sdk';
const healthApi = api('health');
// Key-value store to test connectivity (replace with your actual Nitric resource)
const healthStore = kv('health-check').allow('get', 'set');
interface HealthCheck {
name: string;
status: 'ok' | 'error';
message?: string;
}
interface HealthResponse {
status: 'ok' | 'degraded';
timestamp: string;
provider: string;
checks: HealthCheck[];
}
healthApi.get('/health', async (ctx) => {
const checks: HealthCheck[] = [];
let degraded = false;
// Test KV store connectivity
try {
await healthStore.set('heartbeat', { ts: new Date().toISOString() });
checks.push({ name: 'kv_store', status: 'ok' });
} catch (err) {
checks.push({
name: 'kv_store',
status: 'error',
message: err instanceof Error ? err.message : String(err),
});
degraded = true;
}
// Test an upstream HTTP dependency
const upstreamUrl = process.env.UPSTREAM_API_URL;
if (upstreamUrl) {
try {
const resp = await fetch(`${upstreamUrl}/ping`, {
signal: AbortSignal.timeout(5000),
});
checks.push({
name: 'upstream_api',
status: resp.ok ? 'ok' : 'error',
message: resp.ok ? undefined : `HTTP ${resp.status}`,
});
if (!resp.ok) degraded = true;
} catch (err) {
checks.push({
name: 'upstream_api',
status: 'error',
message: err instanceof Error ? err.message : String(err),
});
degraded = true;
}
}
const body: HealthResponse = {
status: degraded ? 'degraded' : 'ok',
timestamp: new Date().toISOString(),
provider: process.env.NITRIC_ENVIRONMENT ?? 'local',
checks,
};
ctx.res.status = degraded ? 503 : 200;
ctx.res.json(body);
return ctx;
});
Register the service in your nitric.yaml:
# nitric.yaml
name: my-app
services:
- match: services/*.ts
start: ts-node $SERVICE_PATH
Test locally with the Nitric dev server:
nitric start
curl http://localhost:4001/health
{
"status": "ok",
"timestamp": "2026-07-06T10:00:00.000Z",
"provider": "local",
"checks": [
{ "name": "kv_store", "status": "ok" },
{ "name": "upstream_api", "status": "ok" }
]
}
Step 2: Configure Vigilmon HTTP Monitor
After deploying with nitric up, find the API Gateway URL from your cloud provider console or the Nitric deployment output, then configure the monitor:
- Log in to Vigilmon → Add Monitor → HTTP.
- URL:
https://your-api-gateway-url.example.com/health - Check interval: 60 seconds.
- Response timeout: 10 seconds.
- Expected status code:
200. - Keyword assertion:
"status":"ok"— catches degraded responses even when the service returns HTTP 200. - Click Save.
Vigilmon probes from multiple external locations. It requires a quorum of probe locations to agree on a failure before alerting — this prevents false positives from transient regional issues that have nothing to do with your application.
Multi-cloud monitoring with Nitric
Nitric's portability means you may deploy the same service to different providers in different environments. Create a Vigilmon monitor per deployment:
| Environment | Provider | URL | Interval |
|---|---|---|---|
| Production | AWS | https://abc.execute-api.us-east-1.amazonaws.com/health | 60 s |
| Staging | GCP | https://xyz.run.app/health | 120 s |
| DR | Azure | https://def.azurewebsites.net/health | 60 s |
Group monitors by environment using Vigilmon Monitor groups.
Step 3: Heartbeat Monitor for Nitric Scheduled Tasks
Nitric's schedule() primitive defines cron-style tasks. Use a Vigilmon heartbeat monitor to detect when a scheduled task silently stops executing.
// services/cleanup.ts
import { schedule } from '@nitric/sdk';
// Runs every hour
schedule('hourly-cleanup').every('1 hours', async () => {
try {
const count = await runCleanup();
console.log(`Cleanup complete: ${count} records processed`);
// Ping Vigilmon heartbeat on success
await pingHeartbeat();
} catch (err) {
console.error('Cleanup failed:', err);
// Do NOT ping the heartbeat — the lapsed heartbeat will trigger a Vigilmon alert
throw err;
}
});
async function runCleanup(): 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, {
method: 'POST',
signal: AbortSignal.timeout(5000),
});
} 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). If the scheduled task stops running, the heartbeat lapses and Vigilmon fires an alert.
Store the heartbeat URL as a Nitric secret so it's available at runtime across cloud providers:
// Access the heartbeat URL as a Nitric secret
import { secret } from '@nitric/sdk';
const heartbeatSecret = secret('vigilmon-heartbeat-url').allow('access');
async function pingHeartbeat(): Promise<void> {
try {
const url = await heartbeatSecret.version('latest').access();
await fetch(url.asString(), { method: 'POST', signal: AbortSignal.timeout(5000) });
} catch (err) {
console.warn('Heartbeat ping failed:', err);
}
}
Step 4: Webhook Receiver for Vigilmon Alerts
Add a Nitric API route to receive Vigilmon DOWN/UP webhook events, so your application can react to outage notifications:
// services/webhooks.ts
import { api } from '@nitric/sdk';
const webhookApi = api('webhooks');
interface VigilmonPayload {
monitor_name: string;
status: 'down' | 'up';
url: string;
response_code: number;
checked_at: string;
}
webhookApi.post('/webhook/vigilmon', async (ctx) => {
const payload = ctx.req.json() as VigilmonPayload;
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 team via Slack
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} (HTTP ${payload.response_code})`,
}),
});
}
} else {
console.info('[VIGILMON] Monitor UP', payload.monitor_name);
}
ctx.res.json({ received: true });
return ctx;
});
In Vigilmon → Alerts → Add channel → Webhook, point to https://your-api-gateway-url.example.com/webhook/vigilmon.
Step 5: Alert Routing Strategy
Nitric emits cloud provider-level events for topic deliveries, queue errors, and scheduled task invocations. Vigilmon emits external availability events. These are complementary and should route to different channels.
| Failure mode | Source | Route to |
|---|---|---|
| Cloud function invocation error | Cloud provider logs | Slack #infra-alerts + ticket |
| API Gateway 5xx spike | Cloud metrics | On-call rotation |
| External endpoint down | Vigilmon | PagerDuty + Slack #prod-alerts |
| Scheduled task heartbeat missed | Vigilmon | Slack #infra-ops-critical |
| TLS certificate expiring | Vigilmon | DevOps team |
Configure Vigilmon alert channels under Alerts → Add channel:
- Email: on-call distribution list for critical production services.
- PagerDuty webhook: primary on-call rotation for endpoint outages.
- Slack webhook: real-time notifications for the engineering team.
Step 6: Public Status Page
Your Nitric application may serve APIs consumed by external developers or customers. Give them a transparent view of availability using Vigilmon.
- In Vigilmon → Status Pages → Create.
- Add your production API monitors and scheduled task heartbeat monitors.
- Configure a custom domain (
status.example.com) or use the Vigilmon-provided subdomain. - Add a status badge to your documentation:
<img src="https://vigilmon.online/badge/<monitor-id>.svg" alt="API Status" />
What Vigilmon Adds to a Nitric Application
| Capability | Nitric | Vigilmon | |---|---|---| | Cloud-agnostic resource definitions | Yes | No | | Multi-cloud deployment | Yes | No | | Local development server | Yes | No | | Topic/queue event delivery | Yes | No | | External synthetic HTTP probing | No | Yes | | DNS resolution failure detection | No | Yes | | TLS/SSL certificate expiry alerts | No | Yes | | Scheduled task heartbeat monitoring | No | Yes | | Multi-region uptime probing | No | Yes | | Public status page | No | Yes | | Independent of cloud provider health | No | Yes |
Nitric abstracts cloud infrastructure so your code stays portable across AWS, GCP, and Azure. Vigilmon abstracts the monitoring question that every cloud provider's native tools get wrong: they measure health from inside the data center, not from where your users are. Together they ensure that your cloud-portable application is not just deployable anywhere, but observable from everywhere.
Start monitoring your Nitric application externally today — register free at vigilmon.online.