Your RedwoodJS app went silent at 2 AM. The GraphQL API stopped responding. A Prisma connection pool exhausted itself, and the background job that sends order confirmation emails hasn't run in six hours. Nobody noticed until a customer called support.
RedwoodJS is a full-stack React framework built for the serverless era — Prisma on the database side, GraphQL in the middle, and React cells on the frontend. It's designed to be "The One True Full-Stack App Framework" — but full-stack means both layers can break. Vigilmon gives you the external, independent monitor that watches your RedwoodJS app from outside your own infrastructure.
This tutorial covers monitoring a RedwoodJS app end-to-end with Vigilmon.
What You'll Build
- A health check function in
api/src/functions/ - A Vigilmon HTTP monitor with assertion
- A Vigilmon heartbeat monitor for background jobs
- Alert channels and a status page
Prerequisites
- A RedwoodJS app (v7.x or later, Node.js 20+)
- A free account at vigilmon.online
Step 1: Create a Health Check Function
RedwoodJS custom API functions live in api/src/functions/. Each file exports a handler that Redwood maps to a serverless function or an Express route, depending on your deployment target.
Create api/src/functions/health.ts:
// api/src/functions/health.ts
import type { APIGatewayEvent, Context } from "aws-lambda";
import { db } from "src/lib/db";
export const handler = async (_event: APIGatewayEvent, _context: Context) => {
const checks: Record<string, string> = {};
let healthy = true;
// 1. Database probe via Prisma
try {
await db.$queryRaw`SELECT 1`;
checks.database = "ok";
} catch (e) {
checks.database = `error: ${(e as Error).message}`;
healthy = false;
}
// 2. Environment sanity check
const requiredEnvVars = ["DATABASE_URL", "SESSION_SECRET"];
const missing = requiredEnvVars.filter((v) => !process.env[v]);
if (missing.length > 0) {
checks.env = `missing: ${missing.join(", ")}`;
healthy = false;
} else {
checks.env = "ok";
}
return {
statusCode: healthy ? 200 : 503,
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
status: healthy ? "ok" : "degraded",
checks,
ts: new Date().toISOString(),
}),
};
};
The db.$queryRaw\SELECT 1`` probe exercises the Prisma connection pool with the cheapest possible query. If the database is unreachable, the connection pool is exhausted, or DATABASE_URL is misconfigured, this will fail and return a 503.
Test locally with yarn rw dev running:
curl http://localhost:8911/health
Expected response:
{
"status": "ok",
"checks": {
"database": "ok",
"env": "ok"
},
"ts": "2026-01-15T10:23:00.000Z"
}
Step 2: Deploy and Expose the Endpoint
If you deploy to Netlify Functions or Vercel Serverless, Redwood maps api/src/functions/health.ts to /.netlify/functions/health or /api/health automatically. If you're on a Node.js server via yarn rw serve, the endpoint is at /api/health.
Check your deployment target's URL. For Netlify:
https://your-app.netlify.app/.netlify/functions/health
For Vercel or a custom server:
https://your-app.com/api/health
Step 3: Set Up a Vigilmon HTTP Monitor
- Log in to Vigilmon and click New Monitor → HTTP.
- Set URL to your health function endpoint.
- Set Check interval to 60 seconds.
- Set Expected status code to
200. - Under Advanced → JSON body assertion, add:
- Path:
status - Expected value:
ok
- Path:
- Save the monitor.
Vigilmon polls from multiple external regions. If your Prisma pool drains, a cold start hangs, or your function crashes entirely, you'll get an alert within 60 seconds.
Step 4: Monitor the GraphQL Endpoint
RedwoodJS's GraphQL API is the primary interface for your frontend cells. A broken resolver, a missing directive, or a schema mismatch can cause the entire API layer to return errors while your health function stays green.
Add a second monitor:
- Click New Monitor → HTTP in Vigilmon.
- Set URL to
https://your-app.com/api/graphql. - Set Method to
POST. - Under Request Body, add a simple introspection query:
{
"query": "{ __typename }"
}
- Add a header:
Content-Type: application/json. - Set Expected status code to
200. - Under Advanced → Keyword check:
- Keyword present:
"__typename" - Keyword absent:
"errors"
- Keyword present:
- Save.
This verifies that your GraphQL schema is healthy and resolvers aren't crashing on startup.
Step 5: Heartbeat Monitor for Background Jobs
RedwoodJS jobs (scheduled with yarn rw jobs) run as background workers. HTTP monitors can't observe them. Use a heartbeat monitor to detect when jobs stop running.
In your job file:
// api/src/jobs/dailyDigestJob.ts
import { jobs } from "src/lib/jobs";
export const DailyDigestJob = jobs.createJob({
queue: "default",
perform: async () => {
try {
await sendDailyDigestEmails();
// Ping Vigilmon heartbeat on success
const heartbeatUrl = process.env.VIGILMON_HEARTBEAT_URL;
if (heartbeatUrl) {
await fetch(heartbeatUrl, { method: "POST" });
}
} catch (error) {
// No ping on failure — Vigilmon alerts on missed ping
throw error;
}
},
});
async function sendDailyDigestEmails() {
// your email logic
}
Set the environment variable:
VIGILMON_HEARTBEAT_URL=https://vigilmon.online/api/heartbeat/<your-id>
In Vigilmon, create a Heartbeat Monitor and set the grace period slightly longer than your job's schedule interval (e.g., 25 hours for a daily job). If the job runner crashes, the queue empties, or the job throws an unhandled error, Vigilmon will alert you.
Step 6: Alert Channels
Go to Notifications → New Channel in Vigilmon and configure:
- Email — immediate alerts to your on-call inbox
- Webhook — push to Slack, PagerDuty, or Discord
For Slack, paste your incoming webhook URL. A down alert looks like:
🔴 DOWN: your-app.com/.netlify/functions/health
Status: 503 Service Unavailable
Region: EU-West
2 minutes ago
Step 7: Status Page
Go to Status Pages → New Status Page in Vigilmon. Add all three monitors (health function, GraphQL API, and heartbeat) and publish the page. Embed the status badge in your README:

What You've Built
| Scenario | How Vigilmon catches it |
|---|---|
| Prisma connection pool exhausted | Health function returns degraded, alert fires |
| Missing environment variable on deploy | Health function returns env: missing, 503 fires |
| Broken GraphQL resolver on startup | GraphQL monitor returns error body, keyword alert fires |
| Background job runner crashes | Heartbeat misses ping, alert fires |
| Entire API function crashes (OOM, syntax error) | HTTP timeout on health endpoint |
| Database unreachable (network, credentials) | Prisma SELECT 1 fails inside health function |
RedwoodJS's serverless-first design means your app can disappear silently in ways a traditional server never would. Vigilmon gives you the external view that catches failures no matter which layer breaks.
Start monitoring your RedwoodJS app today — register free at vigilmon.online.