Monitoring Your Payload CMS App with Vigilmon (Free, Multi-Region)
Payload CMS is the headless CMS built for the TypeScript ecosystem. It runs natively inside your Next.js app, shares the same database connection, and exposes a full REST and GraphQL API — all without the overhead of a separate service.
That tight integration is its strength. It's also what makes a Payload outage expensive: when Payload goes down, so does your entire Next.js app.
This guide covers how to add a health check route to a Payload app, point Vigilmon at it for external multi-region monitoring, and configure instant alerts so you hear about failures before your users do.
Why Payload monitoring is different
Because Payload is embedded in your Next.js app, it doesn't run as a separate process with its own health endpoint. The health of your Payload instance is the health of your Next.js server — including:
- The Node.js process
- Database connectivity (MongoDB or PostgreSQL)
- The Payload collection API
- The Payload admin UI
A generic HTTP monitor on your homepage URL will tell you if the server is responding. But it won't tell you if the Payload API is returning errors, or if the database connection pool has exhausted. You need a dedicated health route.
Step 1: Add a health route to your Payload app
With Next.js App Router (Payload 3.x)
Payload 3.x runs inside the Next.js App Router. Add a dedicated API route handler:
// app/api/health/route.ts
import { NextResponse } from 'next/server'
import { getPayload } from 'payload'
import config from '@payload-config'
export async function GET() {
try {
const payload = await getPayload({ config })
// Test database connectivity with a lightweight query
await payload.find({
collection: 'users',
limit: 0,
})
return NextResponse.json(
{ status: 'ok', database: 'ok', timestamp: new Date().toISOString() },
{ status: 200 }
)
} catch (error) {
return NextResponse.json(
{ status: 'error', database: 'error', detail: String(error) },
{ status: 503 }
)
}
}
Verify it locally:
curl http://localhost:3000/api/health
# {"status":"ok","database":"ok","timestamp":"2026-06-30T10:00:00.000Z"}
With Payload 2.x (Express-based)
For Payload 2.x running on Express, add a custom route in your server file:
// server.ts
import express from 'express'
import payload from 'payload'
const app = express()
// Health check before Payload initialisation completes
app.get('/api/health', async (req, res) => {
try {
// Probe the database by running a minimal count query
await payload.db.connection.db.command({ ping: 1 })
res.status(200).json({ status: 'ok', database: 'ok' })
} catch (error) {
res.status(503).json({ status: 'error', database: 'error' })
}
})
await payload.init({ express: app, /* ... */ })
app.listen(3000)
Step 2: Set up Vigilmon monitoring
With the health endpoint live, point Vigilmon at it:
- Sign up at vigilmon.online — free tier, no credit card
- Click New Monitor → HTTP
- Enter
https://your-app.com/api/health - Set the check interval (5 minutes on free tier)
- Save
Vigilmon checks from multiple geographic regions. If any region can't reach your endpoint, it opens an incident immediately.
Add a keyword monitor for body validation
Add a second monitor that asserts the response content, not just the HTTP status code:
- New Monitor → Keyword
- URL:
https://your-app.com/api/health - Keyword:
"status":"ok" - If absent, Vigilmon treats it as a failure
This catches the case where your Next.js server returns HTTP 200 (because the server itself is running) but the Payload API layer or database connection is broken.
Recommended monitor set for Payload
| Monitor | URL | Type | What it catches |
|---|---|---|---|
| App health | /api/health | HTTP | Process down, port not responding |
| Database check | /api/health | Keyword | MongoDB/PostgreSQL down |
| Payload admin | /admin | HTTP | Admin UI broken or unreachable |
| GraphQL endpoint | /api/graphql | HTTP | GraphQL layer broken |
Step 3: Monitor the Payload admin panel
The admin panel is the interface your editors and content managers use daily. It can break independently of the API — for example, after a bad deploy that corrupts the admin build.
Add a separate HTTP monitor:
- URL:
https://your-app.com/admin - Type: HTTP
- Expected status:
200
Step 4: Configure alert delivery
Slack:
- Create an incoming webhook in Slack
- In Vigilmon: Notifications → New Channel → Slack
- Paste the webhook URL and enable it on your monitors
Email:
- In Vigilmon: Notifications → New Channel → Email
- Add one or more addresses
When your Payload app goes down, you'll get:
🔴 DOWN: your-app.com/api/health
Status: 503 Service Unavailable
Regions: US-East, EU-West, AP-Southeast
Started: 4 minutes ago
And on recovery:
✅ RECOVERED: your-app.com/api/health is back UP
Total downtime: 9 minutes
Step 5: Add a startup readiness check
Payload can take several seconds to initialise on cold start, especially when running migrations. A health check that fires before Payload is ready will return a misleading error. Add a readiness gate:
// app/api/health/route.ts
import { NextResponse } from 'next/server'
let payloadReady = false
// Called from your Payload onInit hook
export function markReady() {
payloadReady = true
}
export async function GET() {
if (!payloadReady) {
return NextResponse.json(
{ status: 'starting', database: 'unknown' },
{ status: 503 }
)
}
// ... existing health check logic
}
In your Payload config:
// payload.config.ts
import { markReady } from './app/api/health/route'
export default buildConfig({
onInit: async () => {
markReady()
},
// ...
})
This prevents Vigilmon from firing false-positive alerts during deployments or cold starts.
Step 6: Create a public status page
If clients or external developers depend on your Payload-powered API:
- Status Pages → New Status Page in Vigilmon
- Add your health monitors
- Share the public URL with API consumers
What you've built
| What | How |
|---|---|
| Health route | /api/health — custom App Router handler |
| Database check | Lightweight Payload query inside the health route |
| External monitoring | Vigilmon HTTP monitor (multi-region) |
| Body assertion | Vigilmon keyword monitor on "status":"ok" |
| Admin UI check | Separate HTTP monitor on /admin |
| Startup guard | Readiness flag prevents cold-start false positives |
| Instant alerts | Slack/email on down + recovery |
Your Payload CMS is now externally observable. The next time a deployment breaks the database connection, the admin panel fails to build, or the Next.js process crashes under load, you'll know about it before your editors or end users do.
Get started free at vigilmon.online — your first monitor is running in under a minute.